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>Provides access to log entries.</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 Log
030{
031    // ********************************************************************************************
032    // ********************************************************************************************
033    // Class Header Stuff
034    // ********************************************************************************************
035    // ********************************************************************************************
036
037
038    // No Pubic Constructors
039    private Log () { }
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 : Log.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        parameterNames.put("clear", EMPTY_VEC_STR);
078
079        parameterNames.put("disable", EMPTY_VEC_STR);
080
081        parameterNames.put("enable", EMPTY_VEC_STR);
082
083        v = new Vector<String>(1);
084        parameterNames.put("startViolationsReport", v);
085        Collections.addAll(v, new String[]
086        { "config", });
087
088        parameterNames.put("stopViolationsReport", EMPTY_VEC_STR);
089    }
090
091
092    // ********************************************************************************************
093    // ********************************************************************************************
094    // Types - Static Inner Classes
095    // ********************************************************************************************
096    // ********************************************************************************************
097
098    /** Log entry. */
099    public static class LogEntry
100        extends BaseType
101        implements java.io.Serializable
102    {
103        /** For Object Serialization.  java.io.Serializable */
104        protected static final long serialVersionUID = 1;
105        
106        public boolean[] optionals()
107        { return new boolean[] { false, false, false, true, false, true, true, true, true, true, true, }; }
108        
109        /** Log entry source. */
110        public final String source;
111        
112        /** Log entry severity. */
113        public final String level;
114        
115        /** Logged text. */
116        public final String text;
117        
118        /**
119         * <CODE>[No Description Provided by Google]</CODE>
120         * <BR />
121         * <BR /><B>OPTIONAL</B>
122         */
123        public final String category;
124        
125        /** Timestamp when this entry was added. */
126        public final Number timestamp;
127        
128        /**
129         * URL of the resource if known.
130         * <BR />
131         * <BR /><B>OPTIONAL</B>
132         */
133        public final String url;
134        
135        /**
136         * Line number in the resource.
137         * <BR />
138         * <BR /><B>OPTIONAL</B>
139         */
140        public final Integer lineNumber;
141        
142        /**
143         * JavaScript stack trace.
144         * <BR />
145         * <BR /><B>OPTIONAL</B>
146         */
147        public final RunTime.StackTrace stackTrace;
148        
149        /**
150         * Identifier of the network request associated with this entry.
151         * <BR />
152         * <BR /><B>OPTIONAL</B>
153         */
154        public final String networkRequestId;
155        
156        /**
157         * Identifier of the worker associated with this entry.
158         * <BR />
159         * <BR /><B>OPTIONAL</B>
160         */
161        public final String workerId;
162        
163        /**
164         * Call arguments.
165         * <BR />
166         * <BR /><B>OPTIONAL</B>
167         */
168        public final RunTime.RemoteObject[] args;
169        
170        /**
171         * Constructor
172         *
173         * @param source Log entry source.
174         * <BR />Acceptable Values: ["xml", "javascript", "network", "storage", "appcache", "rendering", "security", "deprecation", "worker", "violation", "intervention", "recommendation", "other"]
175         * 
176         * @param level Log entry severity.
177         * <BR />Acceptable Values: ["verbose", "info", "warning", "error"]
178         * 
179         * @param text Logged text.
180         * 
181         * @param category -
182         * <BR />Acceptable Values: ["cors"]
183         * <BR /><B>OPTIONAL</B>
184         * 
185         * @param timestamp Timestamp when this entry was added.
186         * 
187         * @param url URL of the resource if known.
188         * <BR /><B>OPTIONAL</B>
189         * 
190         * @param lineNumber Line number in the resource.
191         * <BR /><B>OPTIONAL</B>
192         * 
193         * @param stackTrace JavaScript stack trace.
194         * <BR /><B>OPTIONAL</B>
195         * 
196         * @param networkRequestId Identifier of the network request associated with this entry.
197         * <BR /><B>OPTIONAL</B>
198         * 
199         * @param workerId Identifier of the worker associated with this entry.
200         * <BR /><B>OPTIONAL</B>
201         * 
202         * @param args Call arguments.
203         * <BR /><B>OPTIONAL</B>
204         */
205        public LogEntry(
206                String source, String level, String text, String category, Number timestamp, 
207                String url, Integer lineNumber, RunTime.StackTrace stackTrace, 
208                String networkRequestId, String workerId, RunTime.RemoteObject[] args
209            )
210        {
211            // Exception-Check(s) to ensure that if any parameters which are not declared as
212            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
213            
214            if (source == null)    THROWS.throwNPE("source");
215            if (level == null)     THROWS.throwNPE("level");
216            if (text == null)      THROWS.throwNPE("text");
217            if (timestamp == null) THROWS.throwNPE("timestamp");
218            
219            // Exception-Check(s) to ensure that if any parameters which must adhere to a
220            // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
221            
222            THROWS.checkIAE(
223                "source", source,
224                "xml", "javascript", "network", "storage", "appcache", "rendering", "security", "deprecation", "worker", "violation", "intervention", "recommendation", "other"
225            );
226            THROWS.checkIAE(
227                "level", level,
228                "verbose", "info", "warning", "error"
229            );
230            THROWS.checkIAE(
231                "category", category,
232                "cors"
233            );
234            
235            this.source            = source;
236            this.level             = level;
237            this.text              = text;
238            this.category          = category;
239            this.timestamp         = timestamp;
240            this.url               = url;
241            this.lineNumber        = lineNumber;
242            this.stackTrace        = stackTrace;
243            this.networkRequestId  = networkRequestId;
244            this.workerId          = workerId;
245            this.args              = args;
246        }
247        
248        /**
249         * JSON Object Constructor
250         * @param jo A Json-Object having data about an instance of {@code 'LogEntry'}.
251         */
252        public LogEntry (JsonObject jo)
253        {
254            this.source            = ReadJSON.getString(jo, "source", false, true);
255            this.level             = ReadJSON.getString(jo, "level", false, true);
256            this.text              = ReadJSON.getString(jo, "text", false, true);
257            this.category          = ReadJSON.getString(jo, "category", true, false);
258            this.timestamp         = ReadNumberJSON.get(jo, "timestamp", false, true);
259            this.url               = ReadJSON.getString(jo, "url", true, false);
260            this.lineNumber        = ReadBoxedJSON.getInteger(jo, "lineNumber", true);
261            this.stackTrace        = ReadJSON.getObject(jo, "stackTrace", RunTime.StackTrace.class, true, false);
262            this.networkRequestId  = ReadJSON.getString(jo, "networkRequestId", true, false);
263            this.workerId          = ReadJSON.getString(jo, "workerId", true, false);
264            this.args = (jo.getJsonArray("args") == null)
265                ? null
266                : RJArrIntoStream.objArr(jo.getJsonArray("args"), null, 0, RunTime.RemoteObject.class).toArray(RunTime.RemoteObject[]::new);
267        
268        }
269        
270        
271        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
272        public boolean equals(Object other)
273        {
274            if (this == other)                       return true;
275            if (other == null)                       return false;
276            if (other.getClass() != this.getClass()) return false;
277        
278            LogEntry o = (LogEntry) other;
279        
280            return
281                    Objects.equals(this.source, o.source)
282                &&  Objects.equals(this.level, o.level)
283                &&  Objects.equals(this.text, o.text)
284                &&  Objects.equals(this.category, o.category)
285                &&  Objects.equals(this.timestamp, o.timestamp)
286                &&  Objects.equals(this.url, o.url)
287                &&  Objects.equals(this.lineNumber, o.lineNumber)
288                &&  Objects.equals(this.stackTrace, o.stackTrace)
289                &&  Objects.equals(this.networkRequestId, o.networkRequestId)
290                &&  Objects.equals(this.workerId, o.workerId)
291                &&  Arrays.deepEquals(this.args, o.args);
292        }
293        
294        /** Generates a Hash-Code for {@code 'this'} instance */
295        public int hashCode()
296        {
297            return
298                    Objects.hashCode(this.source)
299                +   Objects.hashCode(this.level)
300                +   Objects.hashCode(this.text)
301                +   Objects.hashCode(this.category)
302                +   Objects.hashCode(this.timestamp)
303                +   Objects.hashCode(this.url)
304                +   Objects.hashCode(this.lineNumber)
305                +   this.stackTrace.hashCode()
306                +   Objects.hashCode(this.networkRequestId)
307                +   Objects.hashCode(this.workerId)
308                +   Arrays.deepHashCode(this.args);
309        }
310    }
311    
312    /** Violation configuration setting. */
313    public static class ViolationSetting
314        extends BaseType
315        implements java.io.Serializable
316    {
317        /** For Object Serialization.  java.io.Serializable */
318        protected static final long serialVersionUID = 1;
319        
320        public boolean[] optionals()
321        { return new boolean[] { false, false, }; }
322        
323        /** Violation type. */
324        public final String name;
325        
326        /** Time threshold to trigger upon. */
327        public final Number threshold;
328        
329        /**
330         * Constructor
331         *
332         * @param name Violation type.
333         * <BR />Acceptable Values: ["longTask", "longLayout", "blockedEvent", "blockedParser", "discouragedAPIUse", "handler", "recurringHandler"]
334         * 
335         * @param threshold Time threshold to trigger upon.
336         */
337        public ViolationSetting(String name, Number threshold)
338        {
339            // Exception-Check(s) to ensure that if any parameters which are not declared as
340            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
341            
342            if (name == null)      THROWS.throwNPE("name");
343            if (threshold == null) THROWS.throwNPE("threshold");
344            
345            // Exception-Check(s) to ensure that if any parameters which must adhere to a
346            // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
347            
348            THROWS.checkIAE(
349                "name", name,
350                "longTask", "longLayout", "blockedEvent", "blockedParser", "discouragedAPIUse", "handler", "recurringHandler"
351            );
352            
353            this.name       = name;
354            this.threshold  = threshold;
355        }
356        
357        /**
358         * JSON Object Constructor
359         * @param jo A Json-Object having data about an instance of {@code 'ViolationSetting'}.
360         */
361        public ViolationSetting (JsonObject jo)
362        {
363            this.name       = ReadJSON.getString(jo, "name", false, true);
364            this.threshold  = ReadNumberJSON.get(jo, "threshold", false, true);
365        }
366        
367        
368        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
369        public boolean equals(Object other)
370        {
371            if (this == other)                       return true;
372            if (other == null)                       return false;
373            if (other.getClass() != this.getClass()) return false;
374        
375            ViolationSetting o = (ViolationSetting) other;
376        
377            return
378                    Objects.equals(this.name, o.name)
379                &&  Objects.equals(this.threshold, o.threshold);
380        }
381        
382        /** Generates a Hash-Code for {@code 'this'} instance */
383        public int hashCode()
384        {
385            return
386                    Objects.hashCode(this.name)
387                +   Objects.hashCode(this.threshold);
388        }
389    }
390    
391    /** Issued when new message was logged. */
392    public static class entryAdded
393        extends BrowserEvent
394        implements java.io.Serializable
395    {
396        /** For Object Serialization.  java.io.Serializable */
397        protected static final long serialVersionUID = 1;
398        
399        public boolean[] optionals()
400        { return new boolean[] { false, }; }
401        
402        /** The entry. */
403        public final Log.LogEntry entry;
404        
405        /**
406         * Constructor
407         *
408         * @param entry The entry.
409         */
410        public entryAdded(Log.LogEntry entry)
411        {
412            super("Log", "entryAdded", 1);
413            
414            // Exception-Check(s) to ensure that if any parameters which are not declared as
415            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
416            
417            if (entry == null) THROWS.throwNPE("entry");
418            
419            this.entry  = entry;
420        }
421        
422        /**
423         * JSON Object Constructor
424         * @param jo A Json-Object having data about an instance of {@code 'entryAdded'}.
425         */
426        public entryAdded (JsonObject jo)
427        {
428            super("Log", "entryAdded", 1);
429        
430            this.entry  = ReadJSON.getObject(jo, "entry", Log.LogEntry.class, false, true);
431        }
432        
433        
434        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
435        public boolean equals(Object other)
436        {
437            if (this == other)                       return true;
438            if (other == null)                       return false;
439            if (other.getClass() != this.getClass()) return false;
440        
441            entryAdded o = (entryAdded) other;
442        
443            return
444                    Objects.equals(this.entry, o.entry);
445        }
446        
447        /** Generates a Hash-Code for {@code 'this'} instance */
448        public int hashCode()
449        {
450            return
451                    this.entry.hashCode();
452        }
453    }
454    
455    
456    // Counter for keeping the WebSocket Request ID's distinct.
457    private static int counter = 1;
458    
459    /**
460     * Clears the log.
461     * 
462     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
463     * {@link Ret0}&gt;</CODE>
464     *
465     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
466     * browser receives the invocation-request.
467     *
468     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
469     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
470     * {@code >} to ensure the Browser Function has run to completion.
471     */
472    public static Script<String, JsonObject, Ret0> clear()
473    {
474        final int          webSocketID = 28000000 + counter++;
475        final boolean[]    optionals   = new boolean[0];
476        
477        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
478        String requestJSON = WriteJSON.get(
479            parameterTypes.get("clear"),
480            parameterNames.get("clear"),
481            optionals, webSocketID,
482            "Log.clear"
483        );
484        
485        // This Remote Command does not have a Return-Value.
486        return new Script<>
487            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
488    }
489    
490    /**
491     * Disables log domain, prevents further log entries from being reported to the client.
492     * 
493     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
494     * {@link Ret0}&gt;</CODE>
495     *
496     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
497     * browser receives the invocation-request.
498     *
499     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
500     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
501     * {@code >} to ensure the Browser Function has run to completion.
502     */
503    public static Script<String, JsonObject, Ret0> disable()
504    {
505        final int          webSocketID = 28001000 + counter++;
506        final boolean[]    optionals   = new boolean[0];
507        
508        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
509        String requestJSON = WriteJSON.get(
510            parameterTypes.get("disable"),
511            parameterNames.get("disable"),
512            optionals, webSocketID,
513            "Log.disable"
514        );
515        
516        // This Remote Command does not have a Return-Value.
517        return new Script<>
518            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
519    }
520    
521    /**
522     * Enables log domain, sends the entries collected so far to the client by means of the
523     * <CODE>entryAdded</CODE> notification.
524     * 
525     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
526     * {@link Ret0}&gt;</CODE>
527     *
528     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
529     * browser receives the invocation-request.
530     *
531     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
532     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
533     * {@code >} to ensure the Browser Function has run to completion.
534     */
535    public static Script<String, JsonObject, Ret0> enable()
536    {
537        final int          webSocketID = 28002000 + counter++;
538        final boolean[]    optionals   = new boolean[0];
539        
540        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
541        String requestJSON = WriteJSON.get(
542            parameterTypes.get("enable"),
543            parameterNames.get("enable"),
544            optionals, webSocketID,
545            "Log.enable"
546        );
547        
548        // This Remote Command does not have a Return-Value.
549        return new Script<>
550            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
551    }
552    
553    /**
554     * start violation reporting.
555     * 
556     * @param config Configuration for violations.
557     * 
558     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
559     * {@link Ret0}&gt;</CODE>
560     *
561     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
562     * browser receives the invocation-request.
563     *
564     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
565     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
566     * {@code >} to ensure the Browser Function has run to completion.
567     */
568    public static Script<String, JsonObject, Ret0> startViolationsReport
569        (Log.ViolationSetting[] config)
570    {
571        // Exception-Check(s) to ensure that if any parameters which are not declared as
572        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
573        
574        if (config == null) THROWS.throwNPE("config");
575        
576        final int       webSocketID = 28003000 + counter++;
577        final boolean[] optionals   = { false, };
578        
579        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
580        String requestJSON = WriteJSON.get(
581            parameterTypes.get("startViolationsReport"),
582            parameterNames.get("startViolationsReport"),
583            optionals, webSocketID,
584            "Log.startViolationsReport",
585            (Object) config
586        );
587        
588        // This Remote Command does not have a Return-Value.
589        return new Script<>
590            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
591    }
592    
593    /**
594     * Stop violation reporting.
595     * 
596     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
597     * {@link Ret0}&gt;</CODE>
598     *
599     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
600     * browser receives the invocation-request.
601     *
602     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
603     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
604     * {@code >} to ensure the Browser Function has run to completion.
605     */
606    public static Script<String, JsonObject, Ret0> stopViolationsReport()
607    {
608        final int          webSocketID = 28004000 + counter++;
609        final boolean[]    optionals   = new boolean[0];
610        
611        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
612        String requestJSON = WriteJSON.get(
613            parameterTypes.get("stopViolationsReport"),
614            parameterNames.get("stopViolationsReport"),
615            optionals, webSocketID,
616            "Log.stopViolationsReport"
617        );
618        
619        // This Remote Command does not have a Return-Value.
620        return new Script<>
621            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
622    }
623    
624}