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>Input/Output operations for streams produced by DevTools.</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 IO
030{
031    // ********************************************************************************************
032    // ********************************************************************************************
033    // Class Header Stuff
034    // ********************************************************************************************
035    // ********************************************************************************************
036
037
038    // No Pubic Constructors
039    private IO () { }
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 : IO.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        v = new Vector<String>(1);
078        parameterNames.put("close", v);
079        Collections.addAll(v, new String[]
080        { "handle", });
081
082        v = new Vector<String>(3);
083        parameterNames.put("read", v);
084        Collections.addAll(v, new String[]
085        { "handle", "offset", "size", });
086
087        v = new Vector<String>(1);
088        parameterNames.put("resolveBlob", v);
089        Collections.addAll(v, new String[]
090        { "objectId", });
091    }
092
093
094    // ********************************************************************************************
095    // ********************************************************************************************
096    // Types - Static Inner Classes
097    // ********************************************************************************************
098    // ********************************************************************************************
099
100    // public static class StreamHandle => String
101    
102    
103    // Counter for keeping the WebSocket Request ID's distinct.
104    private static int counter = 1;
105    
106    /**
107     * Close the stream, discard any temporary backing storage.
108     * 
109     * @param handle Handle of the stream to close.
110     * 
111     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
112     * {@link Ret0}&gt;</CODE>
113     *
114     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
115     * browser receives the invocation-request.
116     *
117     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
118     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
119     * {@code >} to ensure the Browser Function has run to completion.
120     */
121    public static Script<String, JsonObject, Ret0> close(String handle)
122    {
123        // Exception-Check(s) to ensure that if any parameters which are not declared as
124        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
125        
126        if (handle == null) BRDPC.throwNPE("handle");
127        
128        final int       webSocketID = 23000000 + counter++;
129        final boolean[] optionals   = { false, };
130        
131        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
132        String requestJSON = WriteJSON.get(
133            parameterTypes.get("close"),
134            parameterNames.get("close"),
135            optionals, webSocketID,
136            "IO.close",
137            handle
138        );
139        
140        // This Remote Command does not have a Return-Value.
141        return new Script<>
142            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
143    }
144    
145    /**
146     * Read a chunk of the stream
147     * 
148     * @param handle Handle of the stream to read.
149     * 
150     * @param offset 
151     * Seek to the specified offset before reading (if not specificed, proceed with offset
152     * following the last read). Some types of streams may only support sequential reads.
153     * <BR /><B>OPTIONAL</B>
154     * 
155     * @param size Maximum number of bytes to read (left upon the agent discretion if not specified).
156     * <BR /><B>OPTIONAL</B>
157     * 
158     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
159     * {@link Ret3}&gt;</CODE>
160     *
161     * <BR /><BR />This {@link Script} may be <B STYLE='color:red'>executed</B> (using 
162     * {@link Script#exec()}), and a {@link Promise} returned.
163     *
164     * <BR /><BR />When the {@code Promise} is <B STYLE='color: red'>awaited</B>
165     * (using {@link Promise#await()}), the {@code Ret3} will subsequently
166     * be returned from that call.
167     * 
168     * <BR /><BR />The <B STYLE='color: red'>returned</B> values are encapsulated
169     * in an instance of <B>{@link Ret3}</B>
170     *
171     * <BR /><BR /><UL CLASS=JDUL>
172     * <LI><CODE><B>Ret3.a:</B> Boolean (<B>base64Encoded</B>)</CODE>
173     *     <BR />Set if the data is base64-encoded
174     *     <BR /><BR /></LI>
175     * <LI><CODE><B>Ret3.b:</B> String (<B>data</B>)</CODE>
176     *     <BR />Data that were read.
177     *     <BR /><BR /></LI>
178     * <LI><CODE><B>Ret3.c:</B> Boolean (<B>eof</B>)</CODE>
179     *     <BR />Set if the end-of-file condition occurred while reading.
180     *     </LI>
181     * </UL>
182     */
183    public static Script<String, JsonObject, Ret3<Boolean, String, Boolean>> read
184        (String handle, Integer offset, Integer size)
185    {
186        // Exception-Check(s) to ensure that if any parameters which are not declared as
187        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
188        
189        if (handle == null) BRDPC.throwNPE("handle");
190        
191        final int       webSocketID = 23001000 + counter++;
192        final boolean[] optionals   = { false, true, true, };
193        
194        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
195        String requestJSON = WriteJSON.get(
196            parameterTypes.get("read"),
197            parameterNames.get("read"),
198            optionals, webSocketID,
199            "IO.read",
200            handle, offset, size
201        );
202        
203        // 'JSON Binding' ... Converts Browser Response-JSON into Java-Type 'Ret3'
204        Function<JsonObject, Ret3<Boolean, String, Boolean>> 
205            responseProcessor = (JsonObject jo) -> new Ret3<>(
206                ReadBoxedJSON.getBoolean(jo, "base64Encoded", true),
207                ReadJSON.getString(jo, "data", false, true),
208                ReadBoxedJSON.getBoolean(jo, "eof", true)
209            );
210        
211        // Pass the 'defaultSender' to Script-Constructor
212        // The sender that is used can be changed before executing script.
213        return new Script<>(BRDPC.defaultSender, webSocketID, requestJSON, responseProcessor);
214    }
215    
216    /**
217     * Return UUID of Blob object specified by a remote object id.
218     * 
219     * @param objectId Object id of a Blob object wrapper.
220     * 
221     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
222     * String&gt;</CODE>
223     * 
224     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
225     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
226     * String&gt;</CODE> will be returned.
227     *
228     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
229     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
230      * may be retrieved.</I>
231     *
232     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
233     * <BR /><BR /><UL CLASS=JDUL>
234     * <LI><CODE>String (<B>uuid</B></CODE>)
235     *     <BR />UUID of the specified Blob.
236     * </LI>
237     * </UL> */
238    public static Script<String, JsonObject, String> resolveBlob(String objectId)
239    {
240        // Exception-Check(s) to ensure that if any parameters which are not declared as
241        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
242        
243        if (objectId == null) BRDPC.throwNPE("objectId");
244        
245        final int       webSocketID = 23002000 + counter++;
246        final boolean[] optionals   = { false, };
247        
248        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
249        String requestJSON = WriteJSON.get(
250            parameterTypes.get("resolveBlob"),
251            parameterNames.get("resolveBlob"),
252            optionals, webSocketID,
253            "IO.resolveBlob",
254            objectId
255        );
256        
257        // 'JSON Binding' ... Converts Browser Response-JSON to 'String'
258        Function<JsonObject, String> responseProcessor = (JsonObject jo) ->
259            ReadJSON.getString(jo, "uuid", false, true);
260        
261        // Pass the 'defaultSender' to Script-Constructor
262        // The sender that is used can be changed before executing script.
263        return new Script<>(BRDPC.defaultSender, webSocketID, requestJSON, responseProcessor);
264    }
265    
266}