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><CODE>[No Description Provided by Google]</CODE></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 Performance
034{
035    // ********************************************************************************************
036    // ********************************************************************************************
037    // Class Header Stuff
038    // ********************************************************************************************
039    // ********************************************************************************************
040
041
042    // No Pubic Constructors
043    private Performance () { }
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 : Performance.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        parameterNames.put("disable", EMPTY_VEC_STR);
082
083        v = new Vector<String>(1);
084        parameterNames.put("enable", v);
085        Collections.addAll(v, new String[]
086        { "timeDomain", });
087
088        v = new Vector<String>(1);
089        parameterNames.put("setTimeDomain", v);
090        Collections.addAll(v, new String[]
091        { "timeDomain", });
092
093        parameterNames.put("getMetrics", EMPTY_VEC_STR);
094    }
095
096
097    // ********************************************************************************************
098    // ********************************************************************************************
099    // Types - Static Inner Classes
100    // ********************************************************************************************
101    // ********************************************************************************************
102
103    /** Run-time execution metric. */
104    public static class Metric
105        extends BaseType
106        implements java.io.Serializable
107    {
108        /** For Object Serialization.  java.io.Serializable */
109        protected static final long serialVersionUID = 1;
110        
111        public boolean[] optionals()
112        { return new boolean[] { false, false, }; }
113        
114        /** Metric name. */
115        public final String name;
116        
117        /** Metric value. */
118        public final Number value;
119        
120        /**
121         * Constructor
122         *
123         * @param name Metric name.
124         * 
125         * @param value Metric value.
126         */
127        public Metric(String name, Number value)
128        {
129            // Exception-Check(s) to ensure that if any parameters which are not declared as
130            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
131            
132            if (name == null)  THROWS.throwNPE("name");
133            if (value == null) THROWS.throwNPE("value");
134            
135            this.name   = name;
136            this.value  = value;
137        }
138        
139        /**
140         * JSON Object Constructor
141         * @param jo A Json-Object having data about an instance of {@code 'Metric'}.
142         */
143        public Metric (JsonObject jo)
144        {
145            this.name   = ReadJSON.getString(jo, "name", false, true);
146            this.value  = ReadNumberJSON.get(jo, "value", false, true);
147        }
148        
149        
150        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
151        public boolean equals(Object other)
152        {
153            if (this == other)                       return true;
154            if (other == null)                       return false;
155            if (other.getClass() != this.getClass()) return false;
156        
157            Metric o = (Metric) other;
158        
159            return
160                    Objects.equals(this.name, o.name)
161                &&  Objects.equals(this.value, o.value);
162        }
163        
164        /** Generates a Hash-Code for {@code 'this'} instance */
165        public int hashCode()
166        {
167            return
168                    Objects.hashCode(this.name)
169                +   Objects.hashCode(this.value);
170        }
171    }
172    
173    /** Current values of the metrics. */
174    public static class metrics
175        extends BrowserEvent
176        implements java.io.Serializable
177    {
178        /** For Object Serialization.  java.io.Serializable */
179        protected static final long serialVersionUID = 1;
180        
181        public boolean[] optionals()
182        { return new boolean[] { false, false, }; }
183        
184        /** Current values of the metrics. */
185        public final Performance.Metric[] metrics;
186        
187        /** Timestamp title. */
188        public final String title;
189        
190        /**
191         * Constructor
192         *
193         * @param metrics Current values of the metrics.
194         * 
195         * @param title Timestamp title.
196         */
197        public metrics(Performance.Metric[] metrics, String title)
198        {
199            super("Performance", "metrics", 2);
200            
201            // Exception-Check(s) to ensure that if any parameters which are not declared as
202            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
203            
204            if (metrics == null) THROWS.throwNPE("metrics");
205            if (title == null)   THROWS.throwNPE("title");
206            
207            this.metrics  = metrics;
208            this.title    = title;
209        }
210        
211        /**
212         * JSON Object Constructor
213         * @param jo A Json-Object having data about an instance of {@code 'metrics'}.
214         */
215        public metrics (JsonObject jo)
216        {
217            super("Performance", "metrics", 2);
218        
219            this.metrics = (jo.getJsonArray("metrics") == null)
220                ? null
221                : RJArrIntoStream.objArr(jo.getJsonArray("metrics"), null, 0, Performance.Metric.class).toArray(Performance.Metric[]::new);
222        
223            this.title    = ReadJSON.getString(jo, "title", false, true);
224        }
225        
226        
227        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
228        public boolean equals(Object other)
229        {
230            if (this == other)                       return true;
231            if (other == null)                       return false;
232            if (other.getClass() != this.getClass()) return false;
233        
234            metrics o = (metrics) other;
235        
236            return
237                    Arrays.deepEquals(this.metrics, o.metrics)
238                &&  Objects.equals(this.title, o.title);
239        }
240        
241        /** Generates a Hash-Code for {@code 'this'} instance */
242        public int hashCode()
243        {
244            return
245                    Arrays.deepHashCode(this.metrics)
246                +   Objects.hashCode(this.title);
247        }
248    }
249    
250    
251    // Counter for keeping the WebSocket Request ID's distinct.
252    private static int counter = 1;
253    
254    /**
255     * Disable collecting and reporting metrics.
256     * 
257     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
258     * {@link Ret0}&gt;</CODE>
259     *
260     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
261     * browser receives the invocation-request.
262     *
263     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
264     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
265     * {@code >} to ensure the Browser Function has run to completion.
266     */
267    public static Script<String, JsonObject, Ret0> disable()
268    {
269        final int          webSocketID = 36000000 + counter++;
270        final boolean[]    optionals   = new boolean[0];
271        
272        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
273        String requestJSON = WriteJSON.get(
274            parameterTypes.get("disable"),
275            parameterNames.get("disable"),
276            optionals, webSocketID,
277            "Performance.disable"
278        );
279        
280        // This Remote Command does not have a Return-Value.
281        return new Script<>
282            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
283    }
284    
285    /**
286     * Enable collecting and reporting metrics.
287     * 
288     * @param timeDomain Time domain to use for collecting and reporting duration metrics.
289     * <BR />Acceptable Values: ["timeTicks", "threadTicks"]
290     * <BR /><B CLASS=Opt>OPTIONAL</B>
291     * 
292     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
293     * {@link Ret0}&gt;</CODE>
294     *
295     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
296     * browser receives the invocation-request.
297     *
298     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
299     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
300     * {@code >} to ensure the Browser Function has run to completion.
301     */
302    public static Script<String, JsonObject, Ret0> enable(String timeDomain)
303    {
304        // Exception-Check(s) to ensure that if any parameters which must adhere to a
305        // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
306        
307        THROWS.checkIAE(
308            "timeDomain", timeDomain,
309            "timeTicks", "threadTicks"
310        );
311        
312        final int       webSocketID = 36001000 + counter++;
313        final boolean[] optionals   = { true, };
314        
315        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
316        String requestJSON = WriteJSON.get(
317            parameterTypes.get("enable"),
318            parameterNames.get("enable"),
319            optionals, webSocketID,
320            "Performance.enable",
321            timeDomain
322        );
323        
324        // This Remote Command does not have a Return-Value.
325        return new Script<>
326            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
327    }
328    
329    /**
330     * Sets time domain to use for collecting and reporting duration metrics.
331     * Note that this must be called before enabling metrics collection. Calling
332     * this method while metrics collection is enabled returns an error.
333     * <BR /><B CLASS=Exp-Top>EXPERIMENTAL</B><B CLASS=Dep-Top>DEPRECATED</B>
334     * 
335     * @param timeDomain Time domain
336     * <BR />Acceptable Values: ["timeTicks", "threadTicks"]
337     * 
338     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
339     * {@link Ret0}&gt;</CODE>
340     *
341     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
342     * browser receives the invocation-request.
343     *
344     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
345     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
346     * {@code >} to ensure the Browser Function has run to completion.
347     */
348    public static Script<String, JsonObject, Ret0> setTimeDomain(String timeDomain)
349    {
350        // Exception-Check(s) to ensure that if any parameters which are not declared as
351        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
352        
353        if (timeDomain == null) THROWS.throwNPE("timeDomain");
354        
355        // Exception-Check(s) to ensure that if any parameters which must adhere to a
356        // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
357        
358        THROWS.checkIAE(
359            "timeDomain", timeDomain,
360            "timeTicks", "threadTicks"
361        );
362        
363        final int       webSocketID = 36002000 + counter++;
364        final boolean[] optionals   = { false, };
365        
366        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
367        String requestJSON = WriteJSON.get(
368            parameterTypes.get("setTimeDomain"),
369            parameterNames.get("setTimeDomain"),
370            optionals, webSocketID,
371            "Performance.setTimeDomain",
372            timeDomain
373        );
374        
375        // This Remote Command does not have a Return-Value.
376        return new Script<>
377            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
378    }
379    
380    /**
381     * Retrieve current values of run-time metrics.
382     * 
383     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
384     * {@link Performance.Metric}[]&gt;</CODE>
385     * 
386     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
387     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
388     * {@link Performance.Metric}[]&gt;</CODE> will be returned.
389     *
390     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
391     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
392      * may be retrieved.</I>
393     *
394     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
395     * <BR /><BR /><UL CLASS=JDUL>
396     * <LI><CODE>{@link Performance.Metric}[] (<B>metrics</B></CODE>)
397     *     <BR />Current values for run-time metrics.
398     * </LI>
399     * </UL> */
400    public static Script<String, JsonObject, Performance.Metric[]> getMetrics()
401    {
402        final int          webSocketID = 36003000 + counter++;
403        final boolean[]    optionals   = new boolean[0];
404        
405        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
406        String requestJSON = WriteJSON.get(
407            parameterTypes.get("getMetrics"),
408            parameterNames.get("getMetrics"),
409            optionals, webSocketID,
410            "Performance.getMetrics"
411        );
412        
413        // 'JSON Binding' ... Converts Browser Response-JSON to 'Performance.Metric[]'
414        Function<JsonObject, Performance.Metric[]> responseProcessor = (JsonObject jo) ->
415            (jo.getJsonArray("metrics") == null)
416                ? null
417                : RJArrIntoStream.objArr(jo.getJsonArray("metrics"), null, 0, Performance.Metric.class).toArray(Performance.Metric[]::new);
418        
419        return new Script<>(webSocketID, requestJSON, responseProcessor);
420    }
421    
422}