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}<String, {@link JsonObject}, 112 * {@link Ret0}></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}<String, {@link JsonObject}, 159 * {@link Ret3}></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}<String, {@link JsonObject}, 222 * String></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><JsonObject, 226 * String></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}