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>Defines commands and events for browser extensions.</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 Extensions 034{ 035 // ******************************************************************************************** 036 // ******************************************************************************************** 037 // Class Header Stuff 038 // ******************************************************************************************** 039 // ******************************************************************************************** 040 041 042 // No Pubic Constructors 043 private Extensions () { } 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 : Extensions.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("loadUnpacked", v); 083 Collections.addAll(v, new String[] 084 { "path", }); 085 086 v = new Vector<String>(1); 087 parameterNames.put("uninstall", v); 088 Collections.addAll(v, new String[] 089 { "id", }); 090 091 v = new Vector<String>(3); 092 parameterNames.put("getStorageItems", v); 093 Collections.addAll(v, new String[] 094 { "id", "storageArea", "keys", }); 095 096 v = new Vector<String>(3); 097 parameterNames.put("removeStorageItems", v); 098 Collections.addAll(v, new String[] 099 { "id", "storageArea", "keys", }); 100 101 v = new Vector<String>(2); 102 parameterNames.put("clearStorageItems", v); 103 Collections.addAll(v, new String[] 104 { "id", "storageArea", }); 105 106 v = new Vector<String>(3); 107 parameterNames.put("setStorageItems", v); 108 Collections.addAll(v, new String[] 109 { "id", "storageArea", "values", }); 110 } 111 112 113 // ******************************************************************************************** 114 // ******************************************************************************************** 115 // Types - Static Inner Classes 116 // ******************************************************************************************** 117 // ******************************************************************************************** 118 119 /** Storage areas. */ 120 public static final String[] StorageArea = 121 { "session", "local", "sync", "managed", }; 122 123 124 // Counter for keeping the WebSocket Request ID's distinct. 125 private static int counter = 1; 126 127 /** 128 * Installs an unpacked extension from the filesystem similar to 129 * --load-extension CLI flags. Returns extension ID once the extension 130 * has been installed. Available if the client is connected using the 131 * --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging 132 * flag is set. 133 * 134 * @param path Absolute file path. 135 * 136 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 137 * String></CODE> 138 * 139 * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using 140 * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE><JsonObject, 141 * String></CODE> will be returned. 142 * 143 * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>, 144 * using {@link Promise#await()}, <I>and the returned result of this Browser Function may 145 * may be retrieved.</I> 146 * 147 * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B> 148 * <BR /><BR /><UL CLASS=JDUL> 149 * <LI><CODE>String (<B>id</B></CODE>) 150 * <BR />Extension id. 151 * </LI> 152 * </UL> */ 153 public static Script<String, JsonObject, String> loadUnpacked(String path) 154 { 155 // Exception-Check(s) to ensure that if any parameters which are not declared as 156 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 157 158 if (path == null) THROWS.throwNPE("path"); 159 160 final int webSocketID = 10000000 + counter++; 161 final boolean[] optionals = { false, }; 162 163 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 164 String requestJSON = WriteJSON.get( 165 parameterTypes.get("loadUnpacked"), 166 parameterNames.get("loadUnpacked"), 167 optionals, webSocketID, 168 "Extensions.loadUnpacked", 169 path 170 ); 171 172 // 'JSON Binding' ... Converts Browser Response-JSON to 'String' 173 Function<JsonObject, String> responseProcessor = (JsonObject jo) -> 174 ReadJSON.getString(jo, "id", false, true); 175 176 return new Script<>(webSocketID, requestJSON, responseProcessor); 177 } 178 179 /** 180 * Uninstalls an unpacked extension (others not supported) from the profile. 181 * Available if the client is connected using the --remote-debugging-pipe flag 182 * and the --enable-unsafe-extension-debugging. 183 * 184 * @param id Extension id. 185 * 186 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 187 * {@link Ret0}></CODE> 188 * 189 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 190 * browser receives the invocation-request. 191 * 192 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 193 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 194 * {@code >} to ensure the Browser Function has run to completion. 195 */ 196 public static Script<String, JsonObject, Ret0> uninstall(String id) 197 { 198 // Exception-Check(s) to ensure that if any parameters which are not declared as 199 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 200 201 if (id == null) THROWS.throwNPE("id"); 202 203 final int webSocketID = 10001000 + counter++; 204 final boolean[] optionals = { false, }; 205 206 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 207 String requestJSON = WriteJSON.get( 208 parameterTypes.get("uninstall"), 209 parameterNames.get("uninstall"), 210 optionals, webSocketID, 211 "Extensions.uninstall", 212 id 213 ); 214 215 // This Remote Command does not have a Return-Value. 216 return new Script<> 217 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 218 } 219 220 /** 221 * Gets data from extension storage in the given {@code storageArea}. If {@code keys} is 222 * specified, these are used to filter the result. 223 * 224 * @param id ID of extension. 225 * 226 * @param storageArea StorageArea to retrieve data from. 227 * 228 * @param keys Keys to retrieve. 229 * <BR /><B CLASS=Opt>OPTIONAL</B> 230 * 231 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 232 * JsonObject></CODE> 233 * 234 * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using 235 * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE><JsonObject, 236 * JsonObject></CODE> will be returned. 237 * 238 * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>, 239 * using {@link Promise#await()}, <I>and the returned result of this Browser Function may 240 * may be retrieved.</I> 241 * 242 * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B> 243 * <BR /><BR /><UL CLASS=JDUL> 244 * <LI><CODE>JsonObject (<B>data</B></CODE>) 245 * <BR />- 246 * </LI> 247 * </UL> */ 248 public static Script<String, JsonObject, JsonObject> getStorageItems 249 (String id, String storageArea, String[] keys) 250 { 251 // Exception-Check(s) to ensure that if any parameters which are not declared as 252 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 253 254 if (id == null) THROWS.throwNPE("id"); 255 if (storageArea == null) THROWS.throwNPE("storageArea"); 256 257 // Exception-Check(s) to ensure that if any parameters which must adhere to a 258 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 259 260 THROWS.checkIAE("storageArea", storageArea, "Extensions.StorageArea", Extensions.StorageArea); 261 262 final int webSocketID = 10002000 + counter++; 263 final boolean[] optionals = { false, false, true, }; 264 265 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 266 String requestJSON = WriteJSON.get( 267 parameterTypes.get("getStorageItems"), 268 parameterNames.get("getStorageItems"), 269 optionals, webSocketID, 270 "Extensions.getStorageItems", 271 id, storageArea, keys 272 ); 273 274 // 'JSON Binding' ... Converts Browser Response-JSON to 'JsonObject' 275 Function<JsonObject, JsonObject> responseProcessor = (JsonObject jo) -> 276 jo.getJsonObject("data"); 277 278 return new Script<>(webSocketID, requestJSON, responseProcessor); 279 } 280 281 /** 282 * Removes {@code keys} from extension storage in the given {@code storageArea}. 283 * 284 * @param id ID of extension. 285 * 286 * @param storageArea StorageArea to remove data from. 287 * 288 * @param keys Keys to remove. 289 * 290 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 291 * {@link Ret0}></CODE> 292 * 293 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 294 * browser receives the invocation-request. 295 * 296 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 297 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 298 * {@code >} to ensure the Browser Function has run to completion. 299 */ 300 public static Script<String, JsonObject, Ret0> removeStorageItems 301 (String id, String storageArea, String[] keys) 302 { 303 // Exception-Check(s) to ensure that if any parameters which are not declared as 304 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 305 306 if (id == null) THROWS.throwNPE("id"); 307 if (storageArea == null) THROWS.throwNPE("storageArea"); 308 if (keys == null) THROWS.throwNPE("keys"); 309 310 // Exception-Check(s) to ensure that if any parameters which must adhere to a 311 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 312 313 THROWS.checkIAE("storageArea", storageArea, "Extensions.StorageArea", Extensions.StorageArea); 314 315 final int webSocketID = 10003000 + counter++; 316 final boolean[] optionals = { false, false, false, }; 317 318 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 319 String requestJSON = WriteJSON.get( 320 parameterTypes.get("removeStorageItems"), 321 parameterNames.get("removeStorageItems"), 322 optionals, webSocketID, 323 "Extensions.removeStorageItems", 324 id, storageArea, keys 325 ); 326 327 // This Remote Command does not have a Return-Value. 328 return new Script<> 329 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 330 } 331 332 /** 333 * Clears extension storage in the given {@code storageArea}. 334 * 335 * @param id ID of extension. 336 * 337 * @param storageArea StorageArea to remove data from. 338 * 339 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 340 * {@link Ret0}></CODE> 341 * 342 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 343 * browser receives the invocation-request. 344 * 345 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 346 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 347 * {@code >} to ensure the Browser Function has run to completion. 348 */ 349 public static Script<String, JsonObject, Ret0> clearStorageItems 350 (String id, String storageArea) 351 { 352 // Exception-Check(s) to ensure that if any parameters which are not declared as 353 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 354 355 if (id == null) THROWS.throwNPE("id"); 356 if (storageArea == null) THROWS.throwNPE("storageArea"); 357 358 // Exception-Check(s) to ensure that if any parameters which must adhere to a 359 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 360 361 THROWS.checkIAE("storageArea", storageArea, "Extensions.StorageArea", Extensions.StorageArea); 362 363 final int webSocketID = 10004000 + counter++; 364 final boolean[] optionals = { false, false, }; 365 366 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 367 String requestJSON = WriteJSON.get( 368 parameterTypes.get("clearStorageItems"), 369 parameterNames.get("clearStorageItems"), 370 optionals, webSocketID, 371 "Extensions.clearStorageItems", 372 id, storageArea 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 * Sets {@code values} in extension storage in the given {@code storageArea}. The provided {@code values} 382 * will be merged with existing values in the storage area. 383 * 384 * @param id ID of extension. 385 * 386 * @param storageArea StorageArea to set data in. 387 * 388 * @param values Values to set. 389 * 390 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 391 * {@link Ret0}></CODE> 392 * 393 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 394 * browser receives the invocation-request. 395 * 396 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 397 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 398 * {@code >} to ensure the Browser Function has run to completion. 399 */ 400 public static Script<String, JsonObject, Ret0> setStorageItems 401 (String id, String storageArea, JsonObject values) 402 { 403 // Exception-Check(s) to ensure that if any parameters which are not declared as 404 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 405 406 if (id == null) THROWS.throwNPE("id"); 407 if (storageArea == null) THROWS.throwNPE("storageArea"); 408 if (values == null) THROWS.throwNPE("values"); 409 410 // Exception-Check(s) to ensure that if any parameters which must adhere to a 411 // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw. 412 413 THROWS.checkIAE("storageArea", storageArea, "Extensions.StorageArea", Extensions.StorageArea); 414 415 final int webSocketID = 10005000 + counter++; 416 final boolean[] optionals = { false, false, false, }; 417 418 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 419 String requestJSON = WriteJSON.get( 420 parameterTypes.get("setStorageItems"), 421 parameterNames.get("setStorageItems"), 422 optionals, webSocketID, 423 "Extensions.setStorageItems", 424 id, storageArea, values 425 ); 426 427 // This Remote Command does not have a Return-Value. 428 return new Script<> 429 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 430 } 431 432}