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><CODE>[No Description Provided by Google]</CODE></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 Database
030{
031    // ********************************************************************************************
032    // ********************************************************************************************
033    // Class Header Stuff
034    // ********************************************************************************************
035    // ********************************************************************************************
036
037
038    // No Pubic Constructors
039    private Database () { }
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 : Database.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("disable", EMPTY_VEC_STR);
078
079        parameterNames.put("enable", EMPTY_VEC_STR);
080
081        v = new Vector<String>(2);
082        parameterNames.put("executeSQL", v);
083        Collections.addAll(v, new String[]
084        { "databaseId", "query", });
085
086        v = new Vector<String>(1);
087        parameterNames.put("getDatabaseTableNames", v);
088        Collections.addAll(v, new String[]
089        { "databaseId", });
090    }
091
092
093    // ********************************************************************************************
094    // ********************************************************************************************
095    // Types - Static Inner Classes
096    // ********************************************************************************************
097    // ********************************************************************************************
098
099    // public static class DatabaseId => String
100    
101    /** Database object. */
102    public static class _Database
103        extends BaseType
104        implements java.io.Serializable
105    {
106        /** For Object Serialization.  java.io.Serializable */
107        protected static final long serialVersionUID = 1;
108        
109        public boolean[] optionals()
110        { return new boolean[] { false, false, false, false, }; }
111        
112        /** Database ID. */
113        public final String id;
114        
115        /** Database domain. */
116        public final String domain;
117        
118        /** Database name. */
119        public final String name;
120        
121        /** Database version. */
122        public final String version;
123        
124        /**
125         * Constructor
126         *
127         * @param id Database ID.
128         * 
129         * @param domain Database domain.
130         * 
131         * @param name Database name.
132         * 
133         * @param version Database version.
134         */
135        public _Database(String id, String domain, String name, String version)
136        {
137            // Exception-Check(s) to ensure that if any parameters which are not declared as
138            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
139            
140            if (id == null)      THROWS.throwNPE("id");
141            if (domain == null)  THROWS.throwNPE("domain");
142            if (name == null)    THROWS.throwNPE("name");
143            if (version == null) THROWS.throwNPE("version");
144            
145            this.id       = id;
146            this.domain   = domain;
147            this.name     = name;
148            this.version  = version;
149        }
150        
151        /**
152         * JSON Object Constructor
153         * @param jo A Json-Object having data about an instance of {@code 'Database'}.
154         */
155        public _Database (JsonObject jo)
156        {
157            this.id       = ReadJSON.getString(jo, "id", false, true);
158            this.domain   = ReadJSON.getString(jo, "domain", false, true);
159            this.name     = ReadJSON.getString(jo, "name", false, true);
160            this.version  = ReadJSON.getString(jo, "version", false, true);
161        }
162        
163        
164        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
165        public boolean equals(Object other)
166        {
167            if (this == other)                       return true;
168            if (other == null)                       return false;
169            if (other.getClass() != this.getClass()) return false;
170        
171            _Database o = (_Database) other;
172        
173            return
174                    Objects.equals(this.id, o.id)
175                &&  Objects.equals(this.domain, o.domain)
176                &&  Objects.equals(this.name, o.name)
177                &&  Objects.equals(this.version, o.version);
178        }
179        
180        /** Generates a Hash-Code for {@code 'this'} instance */
181        public int hashCode()
182        {
183            return
184                    Objects.hashCode(this.id)
185                +   Objects.hashCode(this.domain)
186                +   Objects.hashCode(this.name)
187                +   Objects.hashCode(this.version);
188        }
189    }
190    
191    /** Database error. */
192    public static class Error
193        extends BaseType
194        implements java.io.Serializable
195    {
196        /** For Object Serialization.  java.io.Serializable */
197        protected static final long serialVersionUID = 1;
198        
199        public boolean[] optionals()
200        { return new boolean[] { false, false, }; }
201        
202        /** Error message. */
203        public final String message;
204        
205        /** Error code. */
206        public final int code;
207        
208        /**
209         * Constructor
210         *
211         * @param message Error message.
212         * 
213         * @param code Error code.
214         */
215        public Error(String message, int code)
216        {
217            // Exception-Check(s) to ensure that if any parameters which are not declared as
218            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
219            
220            if (message == null) THROWS.throwNPE("message");
221            
222            this.message  = message;
223            this.code     = code;
224        }
225        
226        /**
227         * JSON Object Constructor
228         * @param jo A Json-Object having data about an instance of {@code 'Error'}.
229         */
230        public Error (JsonObject jo)
231        {
232            this.message  = ReadJSON.getString(jo, "message", false, true);
233            this.code     = ReadPrimJSON.getInt(jo, "code");
234        }
235        
236        
237        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
238        public boolean equals(Object other)
239        {
240            if (this == other)                       return true;
241            if (other == null)                       return false;
242            if (other.getClass() != this.getClass()) return false;
243        
244            Error o = (Error) other;
245        
246            return
247                    Objects.equals(this.message, o.message)
248                &&  (this.code == o.code);
249        }
250        
251        /** Generates a Hash-Code for {@code 'this'} instance */
252        public int hashCode()
253        {
254            return
255                    Objects.hashCode(this.message)
256                +   this.code;
257        }
258    }
259    
260    /** <CODE>[No Description Provided by Google]</CODE> */
261    public static class addDatabase
262        extends BrowserEvent
263        implements java.io.Serializable
264    {
265        /** For Object Serialization.  java.io.Serializable */
266        protected static final long serialVersionUID = 1;
267        
268        public boolean[] optionals()
269        { return new boolean[] { false, }; }
270        
271        /** <CODE>[No Description Provided by Google]</CODE> */
272        public final Database._Database database;
273        
274        /**
275         * Constructor
276         *
277         * @param database -
278         */
279        public addDatabase(Database._Database database)
280        {
281            super("Database", "addDatabase", 1);
282            
283            // Exception-Check(s) to ensure that if any parameters which are not declared as
284            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
285            
286            if (database == null) THROWS.throwNPE("database");
287            
288            this.database  = database;
289        }
290        
291        /**
292         * JSON Object Constructor
293         * @param jo A Json-Object having data about an instance of {@code 'addDatabase'}.
294         */
295        public addDatabase (JsonObject jo)
296        {
297            super("Database", "addDatabase", 1);
298        
299            this.database  = ReadJSON.getObject(jo, "database", Database._Database.class, false, true);
300        }
301        
302        
303        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
304        public boolean equals(Object other)
305        {
306            if (this == other)                       return true;
307            if (other == null)                       return false;
308            if (other.getClass() != this.getClass()) return false;
309        
310            addDatabase o = (addDatabase) other;
311        
312            return
313                    Objects.equals(this.database, o.database);
314        }
315        
316        /** Generates a Hash-Code for {@code 'this'} instance */
317        public int hashCode()
318        {
319            return
320                    this.database.hashCode();
321        }
322    }
323    
324    
325    // Counter for keeping the WebSocket Request ID's distinct.
326    private static int counter = 1;
327    
328    /**
329     * Disables database tracking, prevents database events from being sent to the client.
330     * 
331     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
332     * {@link Ret0}&gt;</CODE>
333     *
334     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
335     * browser receives the invocation-request.
336     *
337     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
338     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
339     * {@code >} to ensure the Browser Function has run to completion.
340     */
341    public static Script<String, JsonObject, Ret0> disable()
342    {
343        final int          webSocketID = 19000000 + counter++;
344        final boolean[]    optionals   = new boolean[0];
345        
346        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
347        String requestJSON = WriteJSON.get(
348            parameterTypes.get("disable"),
349            parameterNames.get("disable"),
350            optionals, webSocketID,
351            "Database.disable"
352        );
353        
354        // This Remote Command does not have a Return-Value.
355        return new Script<>
356            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
357    }
358    
359    /**
360     * Enables database tracking, database events will now be delivered to the client.
361     * 
362     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
363     * {@link Ret0}&gt;</CODE>
364     *
365     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
366     * browser receives the invocation-request.
367     *
368     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
369     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
370     * {@code >} to ensure the Browser Function has run to completion.
371     */
372    public static Script<String, JsonObject, Ret0> enable()
373    {
374        final int          webSocketID = 19001000 + counter++;
375        final boolean[]    optionals   = new boolean[0];
376        
377        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
378        String requestJSON = WriteJSON.get(
379            parameterTypes.get("enable"),
380            parameterNames.get("enable"),
381            optionals, webSocketID,
382            "Database.enable"
383        );
384        
385        // This Remote Command does not have a Return-Value.
386        return new Script<>
387            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
388    }
389    
390    /**
391     * <CODE>[No Description Provided by Google]</CODE>
392     * 
393     * @param databaseId -
394     * 
395     * @param query -
396     * 
397     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
398     * {@link Ret3}&gt;</CODE>
399     *
400     * <BR /><BR />This {@link Script} may be <B STYLE='color:red'>executed</B> (using 
401     * {@link Script#exec()}), and a {@link Promise} returned.
402     *
403     * <BR /><BR />When the {@code Promise} is <B STYLE='color: red'>awaited</B>
404     * (using {@link Promise#await()}), the {@code Ret3} will subsequently
405     * be returned from that call.
406     * 
407     * <BR /><BR />The <B STYLE='color: red'>returned</B> values are encapsulated
408     * in an instance of <B>{@link Ret3}</B>
409     *
410     * <BR /><BR /><UL CLASS=JDUL>
411     * <LI><CODE><B>Ret3.a:</B> String[] (<B>columnNames</B>)</CODE>
412     *     <BR />-
413     *     <BR /><BR /></LI>
414     * <LI><CODE><B>Ret3.b:</B> JsonArray (<B>values</B>)</CODE>
415     *     <BR />-
416     *     <BR /><BR /></LI>
417     * <LI><CODE><B>Ret3.c:</B> {@link Database.Error} (<B>sqlError</B>)</CODE>
418     *     <BR />-
419     *     </LI>
420     * </UL>
421     */
422    public static Script<String, JsonObject, Ret3<String[], JsonArray, Database.Error>> executeSQL
423        (String databaseId, String query)
424    {
425        // Exception-Check(s) to ensure that if any parameters which are not declared as
426        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
427        
428        if (databaseId == null) THROWS.throwNPE("databaseId");
429        if (query == null)      THROWS.throwNPE("query");
430        
431        final int       webSocketID = 19002000 + counter++;
432        final boolean[] optionals   = { false, false, };
433        
434        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
435        String requestJSON = WriteJSON.get(
436            parameterTypes.get("executeSQL"),
437            parameterNames.get("executeSQL"),
438            optionals, webSocketID,
439            "Database.executeSQL",
440            databaseId, query
441        );
442        
443        // 'JSON Binding' ... Converts Browser Response-JSON into Java-Type 'Ret3'
444        Function<JsonObject, Ret3<String[], JsonArray, Database.Error>> 
445            responseProcessor = (JsonObject jo) -> new Ret3<>(
446                (jo.getJsonArray("columnNames") == null)
447                    ? null
448                    : RJArrIntoStream.strArr(jo.getJsonArray("columnNames"), null, 0).toArray(String[]::new),
449                jo.getJsonArray("values"),
450                ReadJSON.getObject(jo, "sqlError", Database.Error.class, true, false)
451            );
452        
453        return new Script<>(webSocketID, requestJSON, responseProcessor);
454    }
455    
456    /**
457     * <CODE>[No Description Provided by Google]</CODE>
458     * 
459     * @param databaseId -
460     * 
461     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
462     * String[]&gt;</CODE>
463     * 
464     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
465     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
466     * String[]&gt;</CODE> will be returned.
467     *
468     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
469     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
470      * may be retrieved.</I>
471     *
472     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
473     * <BR /><BR /><UL CLASS=JDUL>
474     * <LI><CODE>String[] (<B>tableNames</B></CODE>)
475     *     <BR />-
476     * </LI>
477     * </UL> */
478    public static Script<String, JsonObject, String[]> getDatabaseTableNames(String databaseId)
479    {
480        // Exception-Check(s) to ensure that if any parameters which are not declared as
481        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
482        
483        if (databaseId == null) THROWS.throwNPE("databaseId");
484        
485        final int       webSocketID = 19003000 + counter++;
486        final boolean[] optionals   = { false, };
487        
488        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
489        String requestJSON = WriteJSON.get(
490            parameterTypes.get("getDatabaseTableNames"),
491            parameterNames.get("getDatabaseTableNames"),
492            optionals, webSocketID,
493            "Database.getDatabaseTableNames",
494            databaseId
495        );
496        
497        // 'JSON Binding' ... Converts Browser Response-JSON to 'String[]'
498        Function<JsonObject, String[]> responseProcessor = (JsonObject jo) ->
499            (jo.getJsonArray("tableNames") == null)
500                ? null
501                : RJArrIntoStream.strArr(jo.getJsonArray("tableNames"), null, 0).toArray(String[]::new);
502        
503        return new Script<>(webSocketID, requestJSON, responseProcessor);
504    }
505    
506}