1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233 | package Torello.Browser;
import javax.json.JsonObject;
import java.util.function.Consumer;
import Torello.Java.EXCC;
import Torello.Java.StrPrint;
/**
* <H2>Represents an Internal Java-Side Failure During WebSocket Communication</H2>
*
* This class is used to represent errors that arise during the execution of internal logic
* within the Java-based infrastructure responsible for interacting with the Chrome DevTools
* Protocol (CDP) over WebSockets. It is the conceptual opposite of {@link BrowserError}, which
* represents errors *reported by the browser itself*.
*
* <BR /><BR />
* {@code RDPError} instances are thrown or passed downstream whenever an unexpected or
* invalid condition is detected by the Java-side handlers that process inbound or outbound
* messages on the WebSocket channel.
*
* <BR /><BR />
* These are *not* errors originating from the browser. Instead, they usually reflect one of
* the following situations:
*
* <BR /><BR /><UL CLASS=JDUL>
* <LI>Failures inside message-processing logic (e.g., malformed or unrecognized JSON)</LI>
* <LI>Unchecked runtime exceptions triggered by handler code (e.g., NPE, casting failures)</LI>
* <LI>Unexpected conditions raised by the NeoVisionaries WebSocket implementation</LI>
* <LI>Structural violations in expected CDP response formats</LI>
* </UL>
*
* <BR />{@code RDPError} objects can optionally include:
*
* <BR /><BR /><UL CLASS=JDUL>
* <LI>A textual message describing the failure</LI>
* <LI>The raw {@code JsonObject} that caused the error (if applicable)</LI>
* <LI>A {@code Throwable} that was caught and wrapped</LI>
* </UL>
*
* <BR /><BR /><B CLASS=JDDescLabel2>Causing these Errors:</B>
* <BR />
* All instantiations of this class occur inside one of the four internal infrastructure
* classes:
*
* <BR /><BR /><UL CLASS=JDUL>
*
* <LI> <B><CODE><A HREF='hilite-files/HandleScriptResponse.java.html'>
* HandleScriptResponse</A></CODE></B>
* </LI>
*
* <LI> <B><CODE><A HREF='hilite-files/HandleDispatch.java.html'>
* HandleDispatch</A></CODE></B>
* </LI>
*
* <LI><B><CODE><A HREF='hilite-files/HandleEvent.java.html'>HandleEvent</A></CODE></B></LI>
* <LI><B><CODE><A HREF='hilite-files/WSAdapter.java.html'>WSAdapter</A></CODE></B></LI>
* </UL>
*
* <BR />
* Because these errors reflect misbehavior or malformation in Java-managed logic, they should
* never be ignored. They often signal bugs in parsing logic, protocol desynchronization, or
* incorrect assumptions in command/response handling.
*
* <BR /><BR /><BR /><B CLASS=JDDescLabel2>Registering a Handler:</B>
* <BR />
* To receive instances of this error class, a handler must be registered at the time you create
* your {@link WebSocketSender} using one of the {@code createSender(...)} methods found in either
* {@link BrowserConn#createSender BrowserConn} or {@link PageConn#createSender PageConn}. These
* methods allow you to provide lambda handlers or consumer functions for error callbacks. Without
* explicitly setting a handler for this error type, you will never see these errors—they will be
* silently discarded or ignored by the internal infrastructure.
*
* <BR /><BR />
* Each of the three CDP error/response types — {@link RDPError}, {@link BrowserError}, and
* {@link BrowserEvent} — has its own dedicated handler. These are supplied as {@code Consumer}
* arguments to {@code createSender(...)}, and any logic you wish to perform in response to these
* events must be defined there. The {@code WebSocketSender} will invoke these handlers
* automatically whenever it receives a message of the corresponding kind.
*/
public final class RDPError
implements java.io.Serializable, Comparable<RDPError>
{
/** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */
protected static final long serialVersionUID = 1;
// ********************************************************************************************
// ********************************************************************************************
// Public, Final Fields
// ********************************************************************************************
// ********************************************************************************************
/**
* A descriptive message explaining the nature of the internal error.
*
* <BR /><BR />
* This string is almost always provided by the handler logic itself to contextualize what went
* wrong — e.g., "Unrecognized ID field", "Unexpected type in CDP response", or "Missing
* 'method' property in event dispatch."
*/
public final String message;
/**
* The underlying exception or cause that led to this RDPError.
*
* <BR /><BR />
* This may include {@code NullPointerException}, {@code ClassCastException}, or any
* other unchecked exception that occurred during handler execution. It may be {@code null}
* if the error was raised directly without an underlying Throwable.
*/
public final Throwable cause;
/**
* The raw {@link JsonObject} that was being processed at the time the error occurred.
*
* <BR /><BR />
* This field is useful for debugging. It often contains the browser's CDP response that
* the Java code failed to parse or recognize. It may be {@code null} if the failure was
* unrelated to message content (e.g., a runtime exception).
*/
public final JsonObject jo;
// ********************************************************************************************
// ********************************************************************************************
// Constructors
// ********************************************************************************************
// ********************************************************************************************
RDPError(String message)
{
if (message == null) System.err.println("Input to Error has a null message");
this.message = message;
this.jo = null;
this.cause = null;
}
RDPError(final String message, final JsonObject jo)
{
if (message == null)
System.err.println("Input to RDPError Constructor has a null message");
if (jo == null) System.err.println
("Input to RDPError Constructor has a null JsonObject-Parameter");
this.message = message;
this.jo = jo;
this.cause = null;
}
RDPError(final String message, final Throwable cause)
{
if (message == null) System.err.println
("Input to RDPError Constructor has a null message");
if (cause == null) System.err.println
("Input to RDPError Constructor has a null Throwable-Parameter");
this.message = message;
this.cause = cause;
this.jo = null;
}
RDPError(String message, JsonObject jo, Throwable cause)
{
if (message == null) System.err.println
("Input to RDPError Constructor has a null message");
if (jo == null) System.err.println
("Input to RDPError Constructor has a null JsonObject-Parameter");
if (cause == null) System.err.println
("Input to RDPError Constructor has a null Throwable-Parameter");
this.message = message;
this.jo = jo;
this.cause = cause;
}
// ********************************************************************************************
// ********************************************************************************************
// java.lang.Object, Comparable, Clonable
// ********************************************************************************************
// ********************************************************************************************
@Override
public String toString()
{
final String jsonStr = (jo == null)
? " JSON: NULL"
: (" JSON: \n" + PrintUtil.json2(jo));
final String causeStr = (cause == null)
? " Cause Throwable: NULL"
: (" Cause: \n" + EXCC.toString(cause));
return
"RDPError Object\n" +
"{\n" +
" Message: " + message + '\n' +
jsonStr + '\n' +
causeStr + '\n' +
'}';
}
@Override
public int hashCode()
{ return message.hashCode(); }
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null) return false;
if (this.getClass() != o.getClass()) return false;
final RDPError error = (RDPError) o;
return (message.equals(error.message));
}
@Override
public int compareTo(RDPError error)
{ return this.message.compareTo(error.message); }
}
|