001package Torello.Browser;
002
003import java.util.Objects;
004
005/**
006 * <H2>Represents an Error Sent by the Chrome Browser over WebSocket</H2>
007 *
008 * This class encapsulates error messages originating from the browser itself — not from the Java
009 * side, and not from transport-layer failures (like network disconnects or malformed JSON). These
010 * errors are generated by the browser's internal logic during its processing of a CDP
011 * (Chrome DevTools Protocol) command.
012 *
013 * <BR /><BR />
014 * When the browser receives a CDP command that it cannot process correctly — due to invalid
015 * parameters, internal issues, or unrecognized method calls — it responds over the WebSocket 
016 * channel with a structured error message. This message includes both an error code and a textual
017 * message describing the problem. This class captures and stores that information in a structured
018 * way, so it can be logged, analyzed, or acted upon.
019 *
020 * <BR /><BR />
021 * Importantly, this error is not thrown as a Java exception, nor does it represent a problem in
022 * the Java-side tooling (e.g., parsing, socket I/O, etc.). It is an intentional error response
023 * issued by the browser itself, indicating that a CDP command could not be fulfilled.
024 * 
025 * <BR /><BR /><BR /><B CLASS=JDDescLabel2>Registering a Handler:</B>
026 * <BR />
027 * To receive instances of this error class, a handler must be registered at the time you create
028 * your {@link WebSocketSender} using one of the {@code createSender(...)} methods found in either
029 * {@link BrowserConn#createSender BrowserConn} or {@link PageConn#createSender PageConn}. These
030 * methods allow you to provide lambda handlers or consumer functions for error callbacks. Without
031 * explicitly setting a handler for this error type, you will never see these errors—they will be
032 * silently discarded or ignored by the internal infrastructure.
033 * 
034 * <BR /><BR />
035 * Each of the three CDP error/response types — {@link RDPError}, {@link BrowserError}, and 
036 * {@link BrowserEvent} — has its own dedicated handler. These are supplied as {@code Consumer}
037 * arguments to {@code createSender(...)}, and any logic you wish to perform in response to these
038 * events must be defined there. The {@code WebSocketSender} will invoke these handlers
039 * automatically whenever it receives a message of the corresponding kind.
040 */
041public class BrowserError
042    implements java.io.Serializable, Comparable<BrowserError>
043{
044    /** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */
045    protected static final long serialVersionUID = 1;
046
047
048    // ********************************************************************************************
049    // ********************************************************************************************
050    // Instance Fields
051    // ********************************************************************************************
052    // ********************************************************************************************
053
054
055    /**
056     * The numeric error code assigned by the browser for this error.
057     *
058     * <BR /><BR />
059     * This code is defined internally by the Browser and often (but not always) maps to specific
060     * protocol-related error conditions such as "Invalid Parameters", "Target Not Found",
061     * or "Method Not Implemented."  While not formally documented in all cases, the code can be
062     * used to categorize and respond to common failure cases.
063     */
064    public final int code;
065
066    /**
067     * The textual description of the error as provided by Chrome.
068     *
069     * <BR /><BR />
070     * This message is intended for human readability and often contains hints or clues about why
071     * the CDP command failed. It may mention an unsupported method name, a missing argument, or
072     * some kind of runtime condition that prevented the browser from fulfilling the request.
073     *
074     * <BR /><BR />
075     * While the message is not guaranteed to follow a fixed schema, it is often specific enough to
076     * help diagnose problems—especially when debugging command payloads or execution timing.
077     */
078    public final String message;
079
080    /**
081     * If this error was generated by a known Domain, then it will be savied into this field.  If 
082     * the name is not known, this field will be null.
083     */
084    public final Domains domain;
085
086    /**
087     * If this error was generated by a known Command, then the name of that command is saved into
088     * this field.  If the name is not known, this field will be null.
089     */
090    public final String commandName;
091
092    /** The Json used to build the command. */
093    public final String requestJSONString;
094
095
096    // ********************************************************************************************
097    // ********************************************************************************************
098    // Constructor
099    // ********************************************************************************************
100    // ********************************************************************************************
101
102
103    public BrowserError(final int code, final String message)
104    {
105        this.code               = code;
106        this.message            = message;
107        this.domain             = null;
108        this.commandName        = null;
109        this.requestJSONString  = null;
110    }
111
112    @SuppressWarnings("rawtypes")
113    BrowserError(final Promise promise, final int code, final String message)
114    {
115        this.code               = code;
116        this.message            = message;
117        this.domain             = promise.script.domain;
118        this.commandName        = promise.script.commandName;
119        this.requestJSONString  = promise.script.requestJSONString;
120    }
121
122
123    // ********************************************************************************************
124    // ********************************************************************************************
125    // java.lang.Object, Cloneable, Comarable Methods
126    // ********************************************************************************************
127    // ********************************************************************************************
128
129
130    public String toString()
131    {
132        final String ret =
133            "BrowserError Received:\n" +
134            "{\n" +
135            "    Code:    " + this.code + '\n' +
136            "    Message: " + this.message + '\n';
137
138        if (this.domain == null) return ret + '}';
139
140        return ret + 
141            "    Domain:  " + this.domain.getPackageName() + '\n' +
142            "    Command: " + this.commandName + 
143            '}';
144    }
145
146    public int hashCode()
147    { return this.code + this.message.hashCode(); }
148
149    public boolean equals(Object other)
150    {
151        if (this == other) return true;
152        if (other == null) return false;
153
154        if (this.getClass() != other.getClass()) return false;
155
156        final BrowserError o = (BrowserError) other;
157
158        return
159                (this.code == o.code)
160            &&  Objects.equals(this.message, o.message)
161            &&  Objects.equals(this.domain, o.domain)
162            &&  Objects.equals(this.commandName, o.commandName);
163    }
164
165    public int compareTo(BrowserError error)
166    {
167        if (this.code != error.code)
168            return this.code - error.code;
169
170        return this.message.compareTo(error.message);
171    }
172}