001package Torello.Browser;
002
003import javax.json.JsonObject;
004import java.util.function.Consumer;
005
006import Torello.Java.EXCC;
007import Torello.Java.StrPrint;
008
009
010/**
011 * <H2>Represents an Internal Java-Side Failure During WebSocket Communication</H2>
012 * 
013 * This class is used to represent errors that arise during the execution of internal logic
014 * within the Java-based infrastructure responsible for interacting with the Chrome DevTools
015 * Protocol (CDP) over WebSockets. It is the conceptual opposite of {@link BrowserError}, which
016 * represents errors *reported by the browser itself*.
017 * 
018 * <BR /><BR />
019 * {@code RDPError} instances are thrown or passed downstream whenever an unexpected or
020 * invalid condition is detected by the Java-side handlers that process inbound or outbound
021 * messages on the WebSocket channel.
022 *
023 * <BR /><BR />
024 * These are *not* errors originating from the browser. Instead, they usually reflect one of
025 * the following situations:
026 *
027 * <BR /><BR /><UL CLASS=JDUL>
028 * <LI>Failures inside message-processing logic (e.g., malformed or unrecognized JSON)</LI>
029 * <LI>Unchecked runtime exceptions triggered by handler code (e.g., NPE, casting failures)</LI>
030 * <LI>Unexpected conditions raised by the NeoVisionaries WebSocket implementation</LI>
031 * <LI>Structural violations in expected CDP response formats</LI>
032 * </UL>
033 *
034 * <BR />{@code RDPError} objects can optionally include:
035 *
036 * <BR /><BR /><UL CLASS=JDUL>
037 * <LI>A textual message describing the failure</LI>
038 * <LI>The raw {@code JsonObject} that caused the error (if applicable)</LI>
039 * <LI>A {@code Throwable} that was caught and wrapped</LI>
040 * </UL>
041 * 
042 * <BR /><BR /><B CLASS=JDDescLabel2>Causing these Errors:</B>
043 * <BR />
044 * All instantiations of this class occur inside one of the four internal infrastructure
045 * classes:
046 *
047 * <BR /><BR /><UL CLASS=JDUL>
048 * 
049 * <LI> <B><CODE><A HREF='hilite-files/HandleScriptResponse.java.html'>
050 *      HandleScriptResponse</A></CODE></B>
051 *      </LI>
052 * 
053 * <LI> <B><CODE><A HREF='hilite-files/HandleDispatch.java.html'>
054 *      HandleDispatch</A></CODE></B>
055 *      </LI>
056 * 
057 * <LI><B><CODE><A HREF='hilite-files/HandleEvent.java.html'>HandleEvent</A></CODE></B></LI>
058 * <LI><B><CODE><A HREF='hilite-files/WSAdapter.java.html'>WSAdapter</A></CODE></B></LI>
059 * </UL>
060 *
061 * <BR />
062 * Because these errors reflect misbehavior or malformation in Java-managed logic, they should
063 * never be ignored. They often signal bugs in parsing logic, protocol desynchronization, or
064 * incorrect assumptions in command/response handling.
065 * 
066 * <BR /><BR /><BR /><B CLASS=JDDescLabel2>Registering a Handler:</B>
067 * <BR />
068 * To receive instances of this error class, a handler must be registered at the time you create
069 * your {@link WebSocketSender} using one of the {@code createSender(...)} methods found in either
070 * {@link BrowserConn#createSender BrowserConn} or {@link PageConn#createSender PageConn}. These
071 * methods allow you to provide lambda handlers or consumer functions for error callbacks. Without
072 * explicitly setting a handler for this error type, you will never see these errors—they will be
073 * silently discarded or ignored by the internal infrastructure.
074 * 
075 * <BR /><BR />
076 * Each of the three CDP error/response types — {@link RDPError}, {@link BrowserError}, and 
077 * {@link BrowserEvent} — has its own dedicated handler. These are supplied as {@code Consumer}
078 * arguments to {@code createSender(...)}, and any logic you wish to perform in response to these
079 * events must be defined there. The {@code WebSocketSender} will invoke these handlers
080 * automatically whenever it receives a message of the corresponding kind.
081 */
082public final class RDPError
083    implements java.io.Serializable, Comparable<RDPError>
084{
085    /** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */
086    protected static final long serialVersionUID = 1;
087
088
089    // ********************************************************************************************
090    // ********************************************************************************************
091    // Public, Final Fields
092    // ********************************************************************************************
093    // ********************************************************************************************
094
095
096    /**
097     * A descriptive message explaining the nature of the internal error.
098     *
099     * <BR /><BR />
100     * This string is almost always provided by the handler logic itself to contextualize what went
101     * wrong — e.g., "Unrecognized ID field", "Unexpected type in CDP response", or "Missing
102     * 'method' property in event dispatch."
103     */
104    public final String message;
105
106    /**
107     * The underlying exception or cause that led to this RDPError.
108     *
109     * <BR /><BR />
110     * This may include {@code NullPointerException}, {@code ClassCastException}, or any
111     * other unchecked exception that occurred during handler execution. It may be {@code null}
112     * if the error was raised directly without an underlying Throwable.
113     */
114    public final Throwable cause;
115
116    /**
117     * The raw {@link JsonObject} that was being processed at the time the error occurred.
118     *
119     * <BR /><BR />
120     * This field is useful for debugging. It often contains the browser's CDP response that
121     * the Java code failed to parse or recognize. It may be {@code null} if the failure was
122     * unrelated to message content (e.g., a runtime exception).
123     */
124    public final JsonObject jo;
125
126
127    // ********************************************************************************************
128    // ********************************************************************************************
129    // Constructors
130    // ********************************************************************************************
131    // ********************************************************************************************
132
133
134    RDPError(String message)
135    {
136        if (message == null) System.err.println("Input to Error has a null message");
137
138        this.message    = message;
139        this.jo         = null;
140        this.cause      = null;
141    }
142
143    RDPError(final String message, final JsonObject jo)
144    {
145        if (message == null)
146            System.err.println("Input to RDPError Constructor  has a null message");
147
148        if (jo == null) System.err.println
149            ("Input to RDPError Constructor has a null JsonObject-Parameter");
150
151        this.message    = message;
152        this.jo         = jo;
153        this.cause      = null;
154    }
155
156    RDPError(final String message, final Throwable cause)
157    {
158        if (message == null) System.err.println
159            ("Input to RDPError Constructor  has a null message");
160
161        if (cause == null) System.err.println
162            ("Input to RDPError Constructor has a null Throwable-Parameter");
163
164        this.message    = message;
165        this.cause      = cause;
166        this.jo         = null;
167    }
168
169    RDPError(String message, JsonObject jo, Throwable cause)
170    {
171        if (message == null) System.err.println
172            ("Input to RDPError Constructor  has a null message");
173
174        if (jo == null) System.err.println
175            ("Input to RDPError Constructor has a null JsonObject-Parameter");
176
177        if (cause == null) System.err.println
178            ("Input to RDPError Constructor has a null Throwable-Parameter");
179
180        this.message    = message;
181        this.jo         = jo;
182        this.cause      = cause;
183    }
184
185
186    // ********************************************************************************************
187    // ********************************************************************************************
188    // java.lang.Object, Comparable, Clonable
189    // ********************************************************************************************
190    // ********************************************************************************************
191
192
193    @Override
194    public String toString()
195    {
196        final String jsonStr = (jo == null)
197            ? "    JSON: NULL"
198            : ("    JSON: \n" + PrintUtil.json2(jo));
199
200        final String causeStr = (cause == null)
201            ? "    Cause Throwable: NULL"
202            : ("    Cause: \n" + EXCC.toString(cause));
203
204        return 
205            "RDPError Object\n" +
206            "{\n" +
207                "    Message: " + message + '\n' +
208                jsonStr + '\n' +
209                causeStr + '\n' +
210            '}';
211    }
212
213    @Override
214    public int hashCode()
215    { return message.hashCode(); }
216
217    @Override
218    public boolean equals(Object o)
219    {
220        if (this == o) return true;
221        if (o == null) return false;
222
223        if (this.getClass() != o.getClass()) return false;
224
225        final RDPError error = (RDPError) o;
226
227        return (message.equals(error.message));
228    }
229
230    @Override
231    public int compareTo(RDPError error)
232    { return this.message.compareTo(error.message); }
233}