001package Torello.Browser; 002 003import static Torello.Java.C.BYELLOW; 004import static Torello.Java.C.RESET; 005 006import Torello.JSON.ReadJSON; 007import Torello.JavaDoc.Annotations.LinkJavaSource; 008import NeoVisionaries.WebSockets.WebSocketException; 009 010import java.util.Objects; 011import java.util.stream.Stream; 012 013import java.io.IOException; 014 015import javax.json.JsonObject; 016import javax.json.JsonArray; // javadoc needs this 017 018/** 019 * A class which represents a connection to a particular Page or Tab that has been opened within 020 * the Browser, rather than a connection to the Browser itself. 021 * 022 * <BR /><BR /> 023 * Represents a snapshot of metadata returned from Chrome’s 024 * <B STYLE='color:red;'>{@code /json/version}</B> End-Point. This includes protocol versioning, V8 025 * details, and the root <B>{@link NeoVisionaries.WebSockets.WebSocket WebSocket}</B> {@code URL} 026 * for establishing DevTools sessions. 027 * 028 * <BR /><BR /> 029 * Although this class offers a public constructor, the recommended way to build an instance is via 030 * the {@code static} method: <B>{@link #getAllPageConn getAllPageConn}</B>. This stream of 031 * instances which are returned each contain a few informational fields that were scraped from the 032 * Json-Response to the above mentioned Chrome response object. 033 * 034 * <BR /><BR /><B CLASS=JDDescLabel2>A {@link WebSocketSender} Instance:</B> 035 * 036 * <BR /> 037 * To begin sending CDP commands, it is mandatory to obtain an instance of the 038 * <B>{@link WebSocketSender}</B> class which has been connected to a Web Browser. This instance 039 * should be passed as the sender to any of the available API methods offered by the Domain Classes 040 * in the packages 041 * <B><CODE><A HREF='BrowserAPI/package-summary.html'>BrowserAPI</A></CODE></B> 042 * and / or the classes in 043 * <B><CODE><A HREF='JavaScriptAPI/package-summary.html'>JavaScriptAPI</A></CODE></B>. 044 * You should review the methods exported by each of the domains and classes within those packages, 045 * and note that the <B>{@link Script}</B> objects returned by them expose an 046 * <B>{@link Script#exec}</B> method, which cannot be invoked without an instance of 047 * <B>{@link WebSocketSender}</B>. 048 * 049 * <BR /><BR /> 050 * Obtaining the <B>{@link WebSocketSender}</B> instance can be achieved by invoking 051 * <B>{@link PageConn#createSender PageConn.createSender}</B>, a 052 * method offered by this class. This method initializes a <B>{@link WebSocketSender}</B> which is 053 * connected to the associated <B>{@link #webSocketDebuggerUrl}</B>. That sender can be used to 054 * make invocations into all CDP Domains. 055 * 056 * <BR /><BR /> 057 * The individual fields exported by this class are documented below, and within their respective 058 * documentation. This class, itself, is largely a structured data holder with minimal logic. 059 * Mostly, it parses the Json which is returned by the Web-Browser endpoint 060 * <B STYLE='color:red;'>{@code /json/list}</B> 061 * 062 * <EMBED CLASS='external-html' DATA-FILE-ID=PCBC_CHECKLIST> 063 */ 064@Torello.JavaDoc.Annotations.CSSLinks(FileNames="BrowserAndPageConn.css") 065public class PageConn implements java.io.Serializable, Comparable<PageConn>, Cloneable 066{ 067 /** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */ 068 protected static final long serialVersionUID = 1; 069 070 071 // ******************************************************************************************** 072 // ******************************************************************************************** 073 // Public Fields 074 // ******************************************************************************************** 075 // ******************************************************************************************** 076 077 078 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_ID> */ 079 public final String id; 080 081 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_TYPE> */ 082 public final String type; 083 084 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_TITLE> */ 085 public final String title; 086 087 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_URL> */ 088 public final String url; 089 090 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_DESCRIPTION> */ 091 public final String description; 092 093 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_WS_DEBUG_URL> */ 094 public final String webSocketDebuggerUrl; 095 096 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_DEVTOOLS_URL> */ 097 public final String devtoolsFrontendUrl; 098 099 /** <EMBED CLASS='external-html' DATA-FILE-ID=PC_FAVICON_URL> */ 100 public final String faviconUrl; 101 102 103 // ******************************************************************************************** 104 // ******************************************************************************************** 105 // Package Private Constructors 106 // ******************************************************************************************** 107 // ******************************************************************************************** 108 109 110 /** Constructs an instance of this type. */ 111 public PageConn( 112 final String id, 113 final String type, 114 final String title, 115 final String url, 116 final String description, 117 final String webSocketDebuggerUrl, 118 final String devtoolsFrontendUrl, 119 final String faviconUrl 120 ) 121 { 122 Objects.requireNonNull(webSocketDebuggerUrl, "webSocketDebuggerUrl is null"); 123 124 this.id = id; 125 this.type = type; 126 this.title = title; 127 this.url = url; 128 this.description = description; 129 this.webSocketDebuggerUrl = webSocketDebuggerUrl; 130 this.devtoolsFrontendUrl = devtoolsFrontendUrl; 131 this.faviconUrl = faviconUrl; 132 } 133 134 /** 135 * <EMBED CLASS='external-html' DATA-FILE-ID=PAGE_CONN> 136 * 137 * @param jo Any one of the {@link JsonObject} instqnces that were generated by querying the 138 * HTTP End-Point <B STYLE='color:red;'>{@code /json/list}</B>, and selecting one of pages 139 * listed within the returned {@link JsonArray}. 140 * 141 * @see ReadJSON#getString(JsonObject, String, boolean, boolean) 142 */ 143 public PageConn(final JsonObject jo) 144 { 145 // Boolean #1: 'isOptional' 146 // FALSE ==> throws if Missing 147 // TRUE ==> Assigns Null if Missing 148 // 149 // Boolean #2: 'throwOnNull' 150 // FALSE ==> returns null if Json-Null has been passed 151 // TRUE ==> throws if Json-Null has been passed 152 153 this.id = ReadJSON.getString(jo, "id", false, true); 154 this.type = ReadJSON.getString(jo, "type", false, true); 155 this.title = ReadJSON.getString(jo, "title", true, false); 156 this.url = ReadJSON.getString(jo, "url", false, true); 157 158 this.description = 159 ReadJSON.getString(jo, "description", true, false); 160 161 this.webSocketDebuggerUrl = 162 ReadJSON.getString(jo, "webSocketDebuggerUrl", false, true); 163 164 this.devtoolsFrontendUrl = 165 ReadJSON.getString(jo, "devtoolsFrontendUrl", true, false); 166 167 this.faviconUrl = 168 ReadJSON.getString(jo, "faviconUrl", true, false); 169 } 170 171 172 // ******************************************************************************************** 173 // ******************************************************************************************** 174 // Builder Methods 175 // ******************************************************************************************** 176 // ******************************************************************************************** 177 178 179 /** 180 * Creates a {@link WebSocketSender} connected to the {@link #webSocketDebuggerUrl} for this 181 * tab. This URL is the endpoint that speaks the Chrome DevTools Protocol (CDP). 182 * 183 * @param connRec Messaging settings for this connection 184 */ 185 public WebSocketSender createSender(final ConnRecord connRec) 186 throws IOException, WebSocketException 187 { return new WebSocketSender(this.webSocketDebuggerUrl, connRec); } 188 189 /** 190 * Retrieves all pages from the CDP-RDP endpoint currently open on the named port. 191 * This queries {@code /json/list} and returns a Java-{@code Stream} of the instnces of this 192 * class. 193 * 194 * @param port The DevTools port Chrome is listening on (default is 9222 if {@code null}). 195 * @param quiet If {@code TRUE}, output is shunted. 196 * @return A list of all Open-Pages, as instances of {@code PageConn} 197 */ 198 @LinkJavaSource(handle="PCBuilder") 199 public static Stream<PageConn> getAllPageConn(Integer port, final boolean quiet) 200 { return PCBuilder.getAllPageConn(port, quiet); } 201 202 203 // ******************************************************************************************** 204 // ******************************************************************************************** 205 // java.lang.Object Methods 206 // ******************************************************************************************** 207 // ******************************************************************************************** 208 209 210 @LinkJavaSource(handle="PCHelper", name="toString") 211 public String toString() { return PCHelper.toString(this); } 212 213 @LinkJavaSource(handle="PCHelper", name="hashCode") 214 public int hashCode() { return PCHelper.hashCode(this); } 215 216 @LinkJavaSource(handle="PCHelper", name="equals") 217 public boolean equals(Object o) { return PCHelper.equals(this, o); } 218 219 @LinkJavaSource(handle="PCHelper", name="clone") 220 public PageConn clone() { return PCHelper.clone(this); } 221 222 public int compareTo(PageConn other) 223 { return this.webSocketDebuggerUrl.compareTo(other.webSocketDebuggerUrl); } 224} 225