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