001package Torello.Browser; 002 003import Torello.JavaDoc.Annotations.IntoHTMLTable; 004import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.BlueDither; 005import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.GreenDither; 006 007import Torello.Browser.JsonAST.PPR; 008import Torello.Browser.JsonAST.TypeNode; 009import Torello.Java.UnreachableError; 010 011import Torello.Java.ReadOnly.ReadOnlyMap; 012import Torello.Java.ReadOnly.ROHashMapBuilder; 013import Torello.Java.ReadOnly.ROTreeMapBuilder; 014 015import java.lang.reflect.Field; 016 017import java.util.function.Predicate; 018import java.util.regex.Pattern; 019 020// Needed by JavaDoc only (all of the types are used in JavaDoc) 021import javax.json.*; 022 023 024/** 025 * 💡 Primarily, this class is used by the Code Generator to produce the classes that comprise the 026 * Java Browser-Automation Library. Generating Java Code to interface with a 027 * <B STYLE='color:red;'>"Google Compliant Browser"</B> isn't exactly rocket science, but rather it 028 * is just very tedious and time consuming. When the Code Generator emits a class - that class is 029 * nothing more than a "wrapper" around a "Web Sockets Implementation" for Google Chromes CDP 030 * (Chrome DevTools Protocol). 031 * 032 * <BR /><BR /> 033 * 🧠The reality is that the entire CDP library is based on nothing more than two JSON files that 034 * Google has left on a particular Git-Hub Page. You may search Google for the CDP JSON 035 * specification files, and it will produce a nice page for you. Those JSON files are converted 036 * <B STYLE='color:red;'><I>piece by piece</I></B> from "Json Strings" into actual Java Types. An 037 * "AST Tree" is built from the JSON file, and then that AST is passed to a Code Generator that 038 * "emits" Java Files. 039 * 040 * <BR /><BR /> 041 * <B STYLE='color:red'><I>100% of the files in the BrowserAPI & JavaScriptAPI</I></B> were 042 * produced, themselves, by a Code Generator package that is not actually part of the public 043 * Torello Java-HTML JAR Distribution Library. 044 * 045 * <BR /><BR /> 046 * 📌 This class does nothing more than map a {@code java.lang.String} into a {@code byte} primitive 047 * constant. Why? Implementing a Code Generator that contains quite a few switch statements which 048 * "switch" on a Java {@code 'byte'} is much nicer to look at & read than one which is 049 * repeatedly "switching" on {@code java.lang.String's}. 050 * 051 * <BR /><BR /> 052 * 🚫 It's quite simple really! Only downside (for you, the user) is that I don't actually expose 053 * or provide the Code Generator's Java source code. Sorry, it's just not a useful thing for 054 * anyone except me! (Trust me, you really wouldn't care...) 055 */ 056@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="INTERNAL_USE_JDHBI") 057public class CDPTypes 058{ 059 private CDPTypes() { } 060 061 /** 062 * <BR>CDP In-Browser Type: An actual Data-Object, defined for use by the browser 063 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonObject} 064 * <BR>Java Type: Any one of the scores of Data-Classes inside the Browser & Java-Script 065 * API packages. (These are always a 'nested class' of any domain-class) 066 * <BR>Note: A type that is a "CDP Type" *must* be one of type, event or command-return-types 067 */ 068 @IntoHTMLTable(title="Indicates an In-Browser 'Data-Class'", background=BlueDither) 069 public static final byte CDP_TYPE = 1; 070 071 /** 072 * <BR>CDP In-Browser Type: An array of Browser Types / Objects 073 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 074 * <BR>Java Type: An array of a 'nested-class' data-object 075 */ 076 @IntoHTMLTable(title="An Array of any one In-Browser 'Data-Class'", background=GreenDither) 077 public static final byte CDP_TYPE_ARRAY_1D = CDP_TYPE + 1; 078 079 /** 080 * <BR>CDP In-Browser Type: Unknown, Any 081 * <BR>Web-Sockets Transmisson Layer: The Json-Type Raw-Json 082 * <BR>Java Type: {@link JsonObject} 083 * <BR>Note: There are *VERY FEW* types which are defined as 'Any' or (unknown) 'Object' in 084 * Google's CDP Spec-Files. When it used, you (the user) get to receive the "Raw 085 * JSON Object" that was transmitted via Web-Socket. 086 */ 087 @IntoHTMLTable(title="Unspecified Browser Type - Accepts Any Type!", background=BlueDither) 088 public static final byte RAW_JSON_VALUE = CDP_TYPE_ARRAY_1D + 1; 089 090 091 // ******************************************************************************************** 092 // ******************************************************************************************** 093 // Some Basic-Types 094 // ******************************************************************************************** 095 // ******************************************************************************************** 096 097 098 /** 099 * <BR>CDP In-Browser Type: Integer 100 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonNumber} 101 * <BR>Java Type: Primitive {@code 'int'} 102 */ 103 @IntoHTMLTable(title="Required, Non-Nullable 'int'", background=GreenDither) 104 public static final byte PRIMITIVE_INT = RAW_JSON_VALUE + 1; 105 106 /** 107 * <BR>CDP In-Browser Type: Integer 108 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonNumber} 109 * <BR>Java Type: Boxed-Type {@code java.lang.Integer} 110 */ 111 @IntoHTMLTable(title="Nullabele / Optional Integer", background=BlueDither) 112 public static final byte BOXED_INTEGER = PRIMITIVE_INT + 1; 113 114 /** 115 * <BR>CDP In-Browser Type: Boolean 116 * <BR>Web-Sockets Transmisson Layer: Either {@link JsonValue#TRUE} or {@link JsonValue#FALSE} 117 * <BR>Java Type: Primitive {@code 'boolean'} 118 */ 119 @IntoHTMLTable(title="Required, Non-Nullable boolean", background=GreenDither) 120 public static final byte PRIMITIVE_BOOLEAN = BOXED_INTEGER + 1; 121 122 /** 123 * <BR>CDP In-Browser Type: Boolean 124 * <BR>Web-Sockets Transmisson Layer: Either {@link JsonValue#TRUE} or {@link JsonValue#FALSE} 125 * <BR>Java Type: Boxed-Type {@code java.lang.Boolean} 126 */ 127 @IntoHTMLTable(title="Optional / Nullable boolean", background=BlueDither) 128 public static final byte BOXED_BOOLEAN = PRIMITIVE_BOOLEAN + 1; 129 130 /** 131 * <BR>CDP In-Browser Type: String 132 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonString} 133 * <BR>Java Type: A {@code java.lang.String} 134 */ 135 @IntoHTMLTable(title="String of Characters", background=GreenDither) 136 public static final byte STRING = BOXED_BOOLEAN + 1; 137 138 /** 139 * <BR>CDP In-Browser Type: Unspecified numeric type 140 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonNumber} 141 * <BR>Java Type: Any concrete sub-class of {@code java.lang.Number} 142 */ 143 @IntoHTMLTable(title="Unspecified Numeric Type", background=BlueDither) 144 public static final byte NUMBER = STRING + 1; 145 146 147 // ******************************************************************************************** 148 // ******************************************************************************************** 149 // One-Dimensional Array-Types 150 // ******************************************************************************************** 151 // ******************************************************************************************** 152 153 154 /** 155 * <BR>CDP In-Browser Type: One dimensional integer array 156 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 157 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that input 158 * {@link JsonArray} instances have only valid integers, and no 159 * {@link JsonValue#NULL Json Null's} 160 * <BR>Java Type: Primitive {@code int[]}-Array 161 */ 162 @IntoHTMLTable(title="Type: int[]-Array", background=GreenDither) 163 public static final byte INT_ARRAY_1D = NUMBER + 1; 164 165 /** 166 * <BR>CDP In-Browser Type: One dimensional boolean array 167 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 168 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that input 169 * {@link JsonArray} instances contain only {@link JsonValue#TRUE} or {@link JsonValue#FALSE}, 170 * without any {@link JsonValue#NULL Json Null's} 171 * <BR>Java Type: Primitive {@code boolean[]}-Array 172 */ 173 @IntoHTMLTable(title="Type: boolean[]-Array", background=BlueDither) 174 public static final byte BOOLEAN_ARRAY_1D = INT_ARRAY_1D + 1; 175 176 /** 177 * <BR>CDP In-Browser Type: One dimensional string array 178 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 179 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that the {@link JsonArray} 180 * have only valid {@link JsonString} instances 181 * <BR>Java Type: A {@code java.lang.String[]} 182 */ 183 @IntoHTMLTable(title="Type: String[]-Array", background=GreenDither) 184 public static final byte STRING_ARRAY_1D = BOOLEAN_ARRAY_1D + 1; 185 186 /** 187 * <BR>CDP In-Browser Type: One dimensional numeric array, of an unspecified numeric type 188 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 189 * <BR>Java Type: A {@code Number[]} (may contain any concrete {@code java.lang.Number} subclass) 190 */ 191 @IntoHTMLTable(title="Type: Number[]-Array", background=BlueDither) 192 public static final byte NUMBER_ARRAY_1D = STRING_ARRAY_1D + 1; 193 194 195 // ******************************************************************************************** 196 // ******************************************************************************************** 197 // Two-Dimensional Array-Types 198 // ******************************************************************************************** 199 // ******************************************************************************************** 200 201 202 /** 203 * <BR>CDP In-Browser Type: Two-dimensional integer array 204 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 205 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that the {@link JsonArray} 206 * be a valid 2-D array of arrays. 207 * <BR>Java Type: Primitive, two-dimensioinal {@code int[][]}-Array 208 */ 209 @IntoHTMLTable(title="Type: 2-D int[][]-Array", background=GreenDither) 210 public static final byte INT_ARRAY_2D = NUMBER_ARRAY_1D + 1; 211 212 /** 213 * <BR>CDP In-Browser Type: Two dimensional boolean array 214 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 215 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that the {@link JsonArray} 216 * be a valid 2-D array of arrays. 217 * <BR>Java Type: Primitive, two-dimensioinal {@code boolean[][]}-Array 218 */ 219 @IntoHTMLTable(title="Type: 2-D boolean[][]-Array", background=BlueDither) 220 public static final byte BOOLEAN_ARRAY_2D = INT_ARRAY_2D + 1; 221 222 /** 223 * <BR>CDP In-Browser Type: Two dimensional string array 224 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 225 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that the {@link JsonArray} 226 * be a valid 2-D array of arrays. 227 * <BR>Java Type: Two-dimensional {@code String[][]}-Array 228 */ 229 @IntoHTMLTable(title="Type: 2-D String[][]-Array", background=GreenDither) 230 public static final byte STRING_ARRAY_2D = BOOLEAN_ARRAY_2D + 1; 231 232 /** 233 * <BR>CDP In-Browser Type: Two dimensional numeric array, of an unspecified numeric type 234 * <BR>Web-Sockets Transmisson Layer: The Json-Type {@link JsonArray} 235 * <BR>Expectation: It is <B STYLE='color:red;'><I>expected</I></B> that the {@link JsonArray} 236 * be a valid 2-D array of arrays. 237 * <BR>Java Type: Two-dimensional {@code Number[][]}-Array 238 */ 239 @IntoHTMLTable(title="Type: 2-D Number[][] Array", background=BlueDither) 240 public static final byte NUMBER_ARRAY_2D = STRING_ARRAY_2D + 1; 241 242 243 // ******************************************************************************************** 244 // ******************************************************************************************** 245 // Byte to "Name as a Java String" (A simple "ReadOnlyMap" of Byte -> String) 246 // ******************************************************************************************** 247 // ******************************************************************************************** 248 249 250 /** 251 * The "switch" from a number to string is done using this map. When a Code Generator "emits" 252 * or "outputs" (when it does its thing, and generates Java Source Code), it literally just 253 * goes through the AST and using lots of {@code java.lang.StringBuilder} to build strings. 254 * 255 * <BR /><BR /> 256 * The {@code String's} which are produced, are saved directly to {@code '.java'} files, and 257 * eventually those {@code '.java'} files are compiled using the standard {@code 'javac'} 258 * compiler stage of the Torello Build-Tool, and turned into the {@code '.class'} files offered 259 * by the Java-HTML JAR Library. 260 * 261 * <BR /><BR /><DIV CLASS=JDHint> 262 * Click on the "View Hilited Source" arrow-button '⮫' (directly above) to see how this map 263 * is loaded, using reflection. 264 * 265 * <BR /><BR /> 266 * This particular field does nothing more than map one of the {@code 'byte'} constants, such 267 * as {@link #PRIMITIVE_INT} or {@link #NUMBER_ARRAY_1D} to the Java {@code 'String'} name of 268 * that constant - {@code "PRIMITIVE_INT"} or {@code "NUMBER_ARRAY_1D"}. 269 * </DIV> 270 * 271 * <BR /><DIV CLASS=JDHintAlt> 272 * If you ask "Why?" - again, the classes inside {@code 'BrowserAPI'} and 273 * {@code 'JavaScriptAPI'} have source code that was emitted, 274 * <B STYLE='color:red'><I>automatically</B></I>, and "emitting" Java Code such as 275 * {@code "CDPTypes.PRIMTIVIE_INT"} requires this little map field. 276 * 277 * <BR ><BR /> 278 * It is that simple, but unfortunately, the Java Code Generator which produces the classes in 279 * this API is not part of the public-API, and therefore its source code cannot be viewed. It 280 * mostly "really boring" stuff. The code generator isn't included in the Java-HTML 281 * {@code '.jar'} because it doesn't serve any purpose, other than generating the 282 * {@code '.java'} files inside {@code 'BrowserAPI'} and {@code 'JavaScriptAPI'}. 283 * </DIV> 284 */ 285 public static final ReadOnlyMap<Byte, String> names; 286 287 static 288 { 289 final Field[] fArr = CDPTypes.class.getFields(); 290 final ROHashMapBuilder<Byte, String> rohmb = new ROHashMapBuilder<>(); 291 292 try 293 { 294 for (final Field f : fArr) 295 296 // Only save the static-byte fields within this class! Remember, there are a few 297 // fields which are not actually "byte constants". Skip any field which isn't one 298 // of the byte constants at the top of this class. 299 // 300 // Map-Key: The actual byte-value of the constant (1, 2, 3....) 301 // Map-Value: The actual name of the constant "PRIMITIVE_INT", 302 // "BOOLEAN_ARRAY_1D" etc. 303 304 if (f.getType() == byte.class) 305 rohmb.put((byte) f.getInt(null), f.getName()); 306 } 307 308 309 // This should just never happen, because I only declare "public byte" fields. All fields 310 // which are "byte" are "public", so IllegalAccessError should be, theoretically, perfectly 311 // impossible! 312 // 313 // NOTE: 'IllegalAccessException' is a checked exception, and "UnreachableError" inherits 314 // java.lang.Error, and is therefore, unchecked. 315 316 catch (IllegalAccessException iae) { throw new UnreachableError(iae); } 317 318 names = rohmb.build(); 319 } 320 321 322 // ******************************************************************************************** 323 // ******************************************************************************************** 324 // Java-String to "Byte" 325 // ******************************************************************************************** 326 // ******************************************************************************************** 327 328 329 // This is used inside of the two methods, below. It serves no purpose whatsoever outside of 330 // this class. This class is largely an "internal use only", or a "non-public facing API" 331 // class. The only problems with Java's keyword "public" is that sometimes there are classes 332 // which have to be "public", due to the fact that their methods & fields are used outside of 333 // the package in which they are defined. 334 // 335 // This class is used over & over outside of the package 'Torello.Browser' - where it is 336 // defined. However, actual end-users, themselves, ought never find a need for using it! 337 338 private static final ReadOnlyMap<String, Byte> bytes; 339 340 static 341 { 342 final ROTreeMapBuilder<String, Byte> rotmb = new ROTreeMapBuilder<>(); 343 344 rotmb.put("JsonValue", RAW_JSON_VALUE); 345 rotmb.put("int", PRIMITIVE_INT); 346 rotmb.put("Integer", BOXED_INTEGER); 347 rotmb.put("boolean", PRIMITIVE_BOOLEAN); 348 rotmb.put("Boolean", BOXED_BOOLEAN); 349 rotmb.put("String", STRING); 350 rotmb.put("Number", NUMBER); 351 352 rotmb.put("int[]", INT_ARRAY_1D); 353 rotmb.put("boolean[]", BOOLEAN_ARRAY_1D); 354 rotmb.put("String[]", STRING_ARRAY_1D); 355 rotmb.put("Number[]", NUMBER_ARRAY_1D); 356 357 rotmb.put("int[][]", INT_ARRAY_2D); 358 rotmb.put("boolean[][]", BOOLEAN_ARRAY_2D); 359 rotmb.put("String[][]", STRING_ARRAY_2D); 360 rotmb.put("Number[][]", NUMBER_ARRAY_2D); 361 362 bytes = rotmb.build(); 363 } 364 365 366 // CD types obey this rule - all it says is that things like "Accessibility.AXNode" is a 367 // match. Any class-name (as a string) which is a "nested class" of some other class will 368 // produce a "match" by this predicate. 369 370 private static final Predicate<String> CDP_TYPE_NAME_PREDICATE = 371 Pattern.compile("\\w+\\.\\w+").asPredicate(); 372 373 374 /** 375 * Converts the strings created inside the Json-AST package into a {@code 'byte'} constant 376 * 377 * <BR /><BR /><DIV CLASS=JDHint> 378 * Note that there is one minor "exceptional case" that is handled inside of this method. 379 * Just look at the test for {@code FilterEntry[]}, below, to see how it is handled. It's a 380 * minor nuisance inside of the CDP specs. 381 * </DIV> 382 * 383 * <BR /><BR /><DIV CLASS=JDHintAlt> 384 * This class is used only once, throughout all of the Java-HTML {@code '.jar'}. It may be 385 * found inside the AST node for "types" (see class {@link TypeNode}). Click on the 386 * {@code TypeNode} link, and then click the "View Hilited Source" to see this method's use. 387 * 388 * <BR /><BR /> 389 * It may found inside the package-private constructor for that class. 390 * </DIV> 391 * 392 * @param CTAS The "Computed Type as a String" 393 * 394 * @return A {@code 'byte'} constant which represents that type. If the type is an actual 395 * and reified browser object type, then the {@code 'byte'} constants {@link #CDP_TYPE} or 396 * {@link #CDP_TYPE_ARRAY_1D} are returned instead. 397 * 398 * @throws UnrecognizedCTASError 399 * <EMBED CLASS='external-html' DATA-FILE-ID=CDPTypes.UnrecognizedCTASError> 400 * 401 * @see TypeNode 402 */ 403 public static byte ctasToByte(final String CTAS) 404 { 405 final Byte ret = bytes.get(CTAS); 406 407 if (ret != null) return ret.byteValue(); 408 else if (CTAS.equals("FilterEntry[]")) return CDP_TYPE_ARRAY_1D; 409 else if (CDP_TYPE_NAME_PREDICATE.test(CTAS)) return CDP_TYPE; 410 else throw new UnrecognizedCTASError(CTAS); 411 } 412 413 /** 414 * Converts the strings created inside the Json-AST package into a {@code 'byte'} constant 415 * 416 * <BR /><BR /><DIV CLASS=JDHint> 417 * This class is used only once throughout all of the Java-HTML {@code '.jar'}. It may be 418 * found inside the AST node for "Parameters, Properties & Return-Values" ({@link PPR}). 419 * Click the PPR link, and then click the "View Hilited Source" to see this method's use. 420 * 421 * <BR /><BR /> 422 * It may be found inside the package-private method named "setCTAS(String)" 423 * </DIV> 424 * 425 * @param CTAS The "Computed Type as a String" 426 * @param refNonNull indicates whether the {@link PPR#reference()} returns null 427 * @param refArrayNonNull indicates whether the {@link PPR#referenceArray()} returns null 428 * 429 * @return A {@code 'byte'} constant which represents that type. If the type is an actual 430 * and reified browser object type, then the {@code 'byte'} constants {@link #CDP_TYPE} or 431 * {@link #CDP_TYPE_ARRAY_1D} are returned instead. 432 * 433 * @throws UnrecognizedCTASError 434 * <EMBED CLASS='external-html' DATA-FILE-ID=CDPTypes.UnrecognizedCTASError> 435 * 436 * @see PPR 437 */ 438 public static byte ctasToByte 439 (final String CTAS, final boolean refNonNull, final boolean refArrayNonNull) 440 { 441 final Byte ret = bytes.get(CTAS); 442 443 if (ret != null) return ret.byteValue(); 444 else if (refNonNull) return CDP_TYPE; 445 else if (refArrayNonNull) return CDP_TYPE_ARRAY_1D; 446 else throw new UnrecognizedCTASError(CTAS); 447 } 448 449 450 // ******************************************************************************************** 451 // ******************************************************************************************** 452 // Byte to Java Type-As-String 453 // ******************************************************************************************** 454 // ******************************************************************************************** 455 456 457 /** Switches from a {@code byte} constant to the Java-Type, as a {@code java.lang.String} */ 458 public static final ReadOnlyMap<Byte, String> types; 459 460 static 461 { 462 final ROTreeMapBuilder<Byte, String> rotmb = new ROTreeMapBuilder<>(); 463 464 rotmb.put(RAW_JSON_VALUE, "JsonValue"); 465 rotmb.put(PRIMITIVE_INT, "int"); 466 rotmb.put(BOXED_INTEGER, "Integer"); 467 rotmb.put(PRIMITIVE_BOOLEAN, "boolean"); 468 rotmb.put(BOXED_BOOLEAN, "Boolean"); 469 rotmb.put(STRING, "String"); 470 rotmb.put(NUMBER, "Number"); 471 472 rotmb.put(INT_ARRAY_1D, "int[]"); 473 rotmb.put(BOOLEAN_ARRAY_1D, "boolean[]"); 474 rotmb.put(STRING_ARRAY_1D, "String[]"); 475 rotmb.put(NUMBER_ARRAY_1D, "Number[]"); 476 477 rotmb.put(INT_ARRAY_2D, "int[][]"); 478 rotmb.put(BOOLEAN_ARRAY_2D, "boolean[][]"); 479 rotmb.put(STRING_ARRAY_2D, "String[][]"); 480 rotmb.put(NUMBER_ARRAY_2D, "Number[][]"); 481 482 types = rotmb.build(); 483 } 484}