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>Reporting of performance timeline events, as specified in
024 * https://w3c.github.io/performance-timeline/#dom-performanceobserver.</B></SPAN>
025 * 
026 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE>
027 */
028@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION})
029@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE")
030public class PerformanceTimeline
031{
032    // ********************************************************************************************
033    // ********************************************************************************************
034    // Class Header Stuff
035    // ********************************************************************************************
036    // ********************************************************************************************
037
038
039    // No Pubic Constructors
040    private PerformanceTimeline () { }
041
042    // These two Vector's are used by all the "Methods" exported by this class.  java.lang.reflect
043    // is used to generate the JSON String's.  It saves thousands of lines of Auto-Generated Code.
044    private static final Map<String, Vector<String>>    parameterNames = new HashMap<>();
045    private static final Map<String, Vector<Class<?>>>  parameterTypes = new HashMap<>();
046
047    // Some Methods do not take any parameters - for instance all the "enable()" and "disable()"
048    // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now,
049    // offically, two empty-vectors.  One for String's, and the other for Classes.
050
051    private static final Vector<String>     EMPTY_VEC_STR = new Vector<>();
052    private static final Vector<Class<?>>   EMPTY_VEC_CLASS = new Vector<>();
053
054    static
055    {
056        for (Method m : PerformanceTimeline.class.getMethods())
057        {
058            // This doesn't work!  The parameter names are all "arg0" ... "argN"
059            // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter!
060            //
061            // Vector<String> parameterNamesList = new Vector<>(); -- NOPE!
062
063            Vector<Class<?>> parameterTypesList = new Vector<>();
064        
065            for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType());
066
067            parameterTypes.put(
068                m.getName(),
069                (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS
070            );
071        }
072    }
073
074    static
075    {
076        Vector<String> v = null;
077
078        v = new Vector<String>(1);
079        parameterNames.put("enable", v);
080        Collections.addAll(v, new String[]
081        { "eventTypes", });
082    }
083
084
085    // ********************************************************************************************
086    // ********************************************************************************************
087    // Types - Static Inner Classes
088    // ********************************************************************************************
089    // ********************************************************************************************
090
091    /** See https://github.com/WICG/LargestContentfulPaint and largest_contentful_paint.idl */
092    public static class LargestContentfulPaint
093        extends BaseType
094        implements java.io.Serializable
095    {
096        /** For Object Serialization.  java.io.Serializable */
097        protected static final long serialVersionUID = 1;
098        
099        public boolean[] optionals()
100        { return new boolean[] { false, false, false, true, true, true, }; }
101        
102        /** <CODE>[No Description Provided by Google]</CODE> */
103        public final Number renderTime;
104        
105        /** <CODE>[No Description Provided by Google]</CODE> */
106        public final Number loadTime;
107        
108        /** The number of pixels being painted. */
109        public final Number size;
110        
111        /**
112         * The id attribute of the element, if available.
113         * <BR />
114         * <BR /><B>OPTIONAL</B>
115         */
116        public final String elementId;
117        
118        /**
119         * The URL of the image (may be trimmed).
120         * <BR />
121         * <BR /><B>OPTIONAL</B>
122         */
123        public final String url;
124        
125        /**
126         * <CODE>[No Description Provided by Google]</CODE>
127         * <BR />
128         * <BR /><B>OPTIONAL</B>
129         */
130        public final Integer nodeId;
131        
132        /**
133         * Constructor
134         *
135         * @param renderTime -
136         * 
137         * @param loadTime -
138         * 
139         * @param size The number of pixels being painted.
140         * 
141         * @param elementId The id attribute of the element, if available.
142         * <BR /><B>OPTIONAL</B>
143         * 
144         * @param url The URL of the image (may be trimmed).
145         * <BR /><B>OPTIONAL</B>
146         * 
147         * @param nodeId -
148         * <BR /><B>OPTIONAL</B>
149         */
150        public LargestContentfulPaint(
151                Number renderTime, Number loadTime, Number size, String elementId, String url, 
152                Integer nodeId
153            )
154        {
155            // Exception-Check(s) to ensure that if any parameters which are not declared as
156            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
157            
158            if (renderTime == null) THROWS.throwNPE("renderTime");
159            if (loadTime == null)   THROWS.throwNPE("loadTime");
160            if (size == null)       THROWS.throwNPE("size");
161            
162            this.renderTime  = renderTime;
163            this.loadTime    = loadTime;
164            this.size        = size;
165            this.elementId   = elementId;
166            this.url         = url;
167            this.nodeId      = nodeId;
168        }
169        
170        /**
171         * JSON Object Constructor
172         * @param jo A Json-Object having data about an instance of {@code 'LargestContentfulPaint'}.
173         */
174        public LargestContentfulPaint (JsonObject jo)
175        {
176            this.renderTime  = ReadNumberJSON.get(jo, "renderTime", false, true);
177            this.loadTime    = ReadNumberJSON.get(jo, "loadTime", false, true);
178            this.size        = ReadNumberJSON.get(jo, "size", false, true);
179            this.elementId   = ReadJSON.getString(jo, "elementId", true, false);
180            this.url         = ReadJSON.getString(jo, "url", true, false);
181            this.nodeId      = ReadBoxedJSON.getInteger(jo, "nodeId", true);
182        }
183        
184        
185        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
186        public boolean equals(Object other)
187        {
188            if (this == other)                       return true;
189            if (other == null)                       return false;
190            if (other.getClass() != this.getClass()) return false;
191        
192            LargestContentfulPaint o = (LargestContentfulPaint) other;
193        
194            return
195                    Objects.equals(this.renderTime, o.renderTime)
196                &&  Objects.equals(this.loadTime, o.loadTime)
197                &&  Objects.equals(this.size, o.size)
198                &&  Objects.equals(this.elementId, o.elementId)
199                &&  Objects.equals(this.url, o.url)
200                &&  Objects.equals(this.nodeId, o.nodeId);
201        }
202        
203        /** Generates a Hash-Code for {@code 'this'} instance */
204        public int hashCode()
205        {
206            return
207                    Objects.hashCode(this.renderTime)
208                +   Objects.hashCode(this.loadTime)
209                +   Objects.hashCode(this.size)
210                +   Objects.hashCode(this.elementId)
211                +   Objects.hashCode(this.url)
212                +   Objects.hashCode(this.nodeId);
213        }
214    }
215    
216    /** <CODE>[No Description Provided by Google]</CODE> */
217    public static class LayoutShiftAttribution
218        extends BaseType
219        implements java.io.Serializable
220    {
221        /** For Object Serialization.  java.io.Serializable */
222        protected static final long serialVersionUID = 1;
223        
224        public boolean[] optionals()
225        { return new boolean[] { false, false, true, }; }
226        
227        /** <CODE>[No Description Provided by Google]</CODE> */
228        public final DOM.Rect previousRect;
229        
230        /** <CODE>[No Description Provided by Google]</CODE> */
231        public final DOM.Rect currentRect;
232        
233        /**
234         * <CODE>[No Description Provided by Google]</CODE>
235         * <BR />
236         * <BR /><B>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>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" fiedls 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 />
425         * <BR /><B>OPTIONAL</B>
426         */
427        public final Number duration;
428        
429        /**
430         * <CODE>[No Description Provided by Google]</CODE>
431         * <BR />
432         * <BR /><B>OPTIONAL</B>
433         */
434        public final PerformanceTimeline.LargestContentfulPaint lcpDetails;
435        
436        /**
437         * <CODE>[No Description Provided by Google]</CODE>
438         * <BR />
439         * <BR /><B>OPTIONAL</B>
440         */
441        public final PerformanceTimeline.LayoutShift layoutShiftDetails;
442        
443        /**
444         * Constructor
445         *
446         * @param frameId Identifies the frame that this event is related to. Empty for non-frame targets.
447         * 
448         * @param type 
449         * The event type, as specified in https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype
450         * This determines which of the optional "details" fiedls is present.
451         * 
452         * @param name Name may be empty depending on the type.
453         * 
454         * @param time Time in seconds since Epoch, monotonically increasing within document lifetime.
455         * 
456         * @param duration Event duration, if applicable.
457         * <BR /><B>OPTIONAL</B>
458         * 
459         * @param lcpDetails -
460         * <BR /><B>OPTIONAL</B>
461         * 
462         * @param layoutShiftDetails -
463         * <BR /><B>OPTIONAL</B>
464         */
465        public TimelineEvent(
466                String frameId, String type, String name, Number time, Number duration, 
467                PerformanceTimeline.LargestContentfulPaint lcpDetails, 
468                PerformanceTimeline.LayoutShift layoutShiftDetails
469            )
470        {
471            // Exception-Check(s) to ensure that if any parameters which are not declared as
472            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
473            
474            if (frameId == null) THROWS.throwNPE("frameId");
475            if (type == null)    THROWS.throwNPE("type");
476            if (name == null)    THROWS.throwNPE("name");
477            if (time == null)    THROWS.throwNPE("time");
478            
479            this.frameId             = frameId;
480            this.type                = type;
481            this.name                = name;
482            this.time                = time;
483            this.duration            = duration;
484            this.lcpDetails          = lcpDetails;
485            this.layoutShiftDetails  = layoutShiftDetails;
486        }
487        
488        /**
489         * JSON Object Constructor
490         * @param jo A Json-Object having data about an instance of {@code 'TimelineEvent'}.
491         */
492        public TimelineEvent (JsonObject jo)
493        {
494            this.frameId             = ReadJSON.getString(jo, "frameId", false, true);
495            this.type                = ReadJSON.getString(jo, "type", false, true);
496            this.name                = ReadJSON.getString(jo, "name", false, true);
497            this.time                = ReadNumberJSON.get(jo, "time", false, true);
498            this.duration            = ReadNumberJSON.get(jo, "duration", true, false);
499            this.lcpDetails          = ReadJSON.getObject(jo, "lcpDetails", PerformanceTimeline.LargestContentfulPaint.class, true, false);
500            this.layoutShiftDetails  = ReadJSON.getObject(jo, "layoutShiftDetails", PerformanceTimeline.LayoutShift.class, true, false);
501        }
502        
503        
504        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
505        public boolean equals(Object other)
506        {
507            if (this == other)                       return true;
508            if (other == null)                       return false;
509            if (other.getClass() != this.getClass()) return false;
510        
511            TimelineEvent o = (TimelineEvent) other;
512        
513            return
514                    Objects.equals(this.frameId, o.frameId)
515                &&  Objects.equals(this.type, o.type)
516                &&  Objects.equals(this.name, o.name)
517                &&  Objects.equals(this.time, o.time)
518                &&  Objects.equals(this.duration, o.duration)
519                &&  Objects.equals(this.lcpDetails, o.lcpDetails)
520                &&  Objects.equals(this.layoutShiftDetails, o.layoutShiftDetails);
521        }
522        
523        /** Generates a Hash-Code for {@code 'this'} instance */
524        public int hashCode()
525        {
526            return
527                    Objects.hashCode(this.frameId)
528                +   Objects.hashCode(this.type)
529                +   Objects.hashCode(this.name)
530                +   Objects.hashCode(this.time)
531                +   Objects.hashCode(this.duration)
532                +   this.lcpDetails.hashCode()
533                +   this.layoutShiftDetails.hashCode();
534        }
535    }
536    
537    /** Sent when a performance timeline event is added. See reportPerformanceTimeline method. */
538    public static class timelineEventAdded
539        extends BrowserEvent
540        implements java.io.Serializable
541    {
542        /** For Object Serialization.  java.io.Serializable */
543        protected static final long serialVersionUID = 1;
544        
545        public boolean[] optionals()
546        { return new boolean[] { false, }; }
547        
548        /** <CODE>[No Description Provided by Google]</CODE> */
549        public final PerformanceTimeline.TimelineEvent event;
550        
551        /**
552         * Constructor
553         *
554         * @param event -
555         */
556        public timelineEventAdded(PerformanceTimeline.TimelineEvent event)
557        {
558            super("PerformanceTimeline", "timelineEventAdded", 1);
559            
560            // Exception-Check(s) to ensure that if any parameters which are not declared as
561            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
562            
563            if (event == null) THROWS.throwNPE("event");
564            
565            this.event  = event;
566        }
567        
568        /**
569         * JSON Object Constructor
570         * @param jo A Json-Object having data about an instance of {@code 'timelineEventAdded'}.
571         */
572        public timelineEventAdded (JsonObject jo)
573        {
574            super("PerformanceTimeline", "timelineEventAdded", 1);
575        
576            this.event  = ReadJSON.getObject(jo, "event", PerformanceTimeline.TimelineEvent.class, false, true);
577        }
578        
579        
580        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
581        public boolean equals(Object other)
582        {
583            if (this == other)                       return true;
584            if (other == null)                       return false;
585            if (other.getClass() != this.getClass()) return false;
586        
587            timelineEventAdded o = (timelineEventAdded) other;
588        
589            return
590                    Objects.equals(this.event, o.event);
591        }
592        
593        /** Generates a Hash-Code for {@code 'this'} instance */
594        public int hashCode()
595        {
596            return
597                    this.event.hashCode();
598        }
599    }
600    
601    
602    // Counter for keeping the WebSocket Request ID's distinct.
603    private static int counter = 1;
604    
605    /**
606     * Previously buffered events would be reported before method returns.
607     * See also: timelineEventAdded
608     * 
609     * @param eventTypes 
610     * The types of event to report, as specified in
611     * https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype
612     * The specified filter overrides any previous filters, passing empty
613     * filter disables recording.
614     * Note that not all types exposed to the web platform are currently supported.
615     * 
616     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
617     * {@link Ret0}&gt;</CODE>
618     *
619     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
620     * browser receives the invocation-request.
621     *
622     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
623     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
624     * {@code >} to ensure the Browser Function has run to completion.
625     */
626    public static Script<String, JsonObject, Ret0> enable(String[] eventTypes)
627    {
628        // Exception-Check(s) to ensure that if any parameters which are not declared as
629        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
630        
631        if (eventTypes == null) THROWS.throwNPE("eventTypes");
632        
633        final int       webSocketID = 34000000 + counter++;
634        final boolean[] optionals   = { false, };
635        
636        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
637        String requestJSON = WriteJSON.get(
638            parameterTypes.get("enable"),
639            parameterNames.get("enable"),
640            optionals, webSocketID,
641            "PerformanceTimeline.enable",
642            (Object) eventTypes
643        );
644        
645        // This Remote Command does not have a Return-Value.
646        return new Script<>
647            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
648    }
649    
650}