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
package Torello.Browser;

import java.util.Objects;

/**
 * <H2>Represents an Error Sent by the Chrome Browser over WebSocket</H2>
 *
 * This class encapsulates error messages originating from the browser itself — not from the Java
 * side, and not from transport-layer failures (like network disconnects or malformed JSON). These
 * errors are generated by the browser's internal logic during its processing of a CDP
 * (Chrome DevTools Protocol) command.
 *
 * <BR /><BR />
 * When the browser receives a CDP command that it cannot process correctly — due to invalid
 * parameters, internal issues, or unrecognized method calls — it responds over the WebSocket 
 * channel with a structured error message. This message includes both an error code and a textual
 * message describing the problem. This class captures and stores that information in a structured
 * way, so it can be logged, analyzed, or acted upon.
 *
 * <BR /><BR />
 * Importantly, this error is not thrown as a Java exception, nor does it represent a problem in
 * the Java-side tooling (e.g., parsing, socket I/O, etc.). It is an intentional error response
 * issued by the browser itself, indicating that a CDP command could not be fulfilled.
 * 
 * <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 class BrowserError
    implements java.io.Serializable, Comparable<BrowserError>
{
    /** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */
    protected static final long serialVersionUID = 1;


    // ********************************************************************************************
    // ********************************************************************************************
    // Instance Fields
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * The numeric error code assigned by the browser for this error.
     *
     * <BR /><BR />
     * This code is defined internally by the Browser and often (but not always) maps to specific
     * protocol-related error conditions such as "Invalid Parameters", "Target Not Found",
     * or "Method Not Implemented."  While not formally documented in all cases, the code can be
     * used to categorize and respond to common failure cases.
     */
    public final int code;

    /**
     * The textual description of the error as provided by Chrome.
     *
     * <BR /><BR />
     * This message is intended for human readability and often contains hints or clues about why
     * the CDP command failed. It may mention an unsupported method name, a missing argument, or
     * some kind of runtime condition that prevented the browser from fulfilling the request.
     *
     * <BR /><BR />
     * While the message is not guaranteed to follow a fixed schema, it is often specific enough to
     * help diagnose problems—especially when debugging command payloads or execution timing.
     */
    public final String message;

    /**
     * If this error was generated by a known Domain, then it will be savied into this field.  If 
     * the name is not known, this field will be null.
     */
    public final Domains domain;

    /**
     * If this error was generated by a known Command, then the name of that command is saved into
     * this field.  If the name is not known, this field will be null.
     */
    public final String commandName;

    /** The Json used to build the command. */
    public final String requestJSONString;


    // ********************************************************************************************
    // ********************************************************************************************
    // Constructor
    // ********************************************************************************************
    // ********************************************************************************************


    public BrowserError(final int code, final String message)
    {
        this.code               = code;
        this.message            = message;
        this.domain             = null;
        this.commandName        = null;
        this.requestJSONString  = null;
    }

    @SuppressWarnings("rawtypes")
    BrowserError(final Promise promise, final int code, final String message)
    {
        this.code               = code;
        this.message            = message;
        this.domain             = promise.script.domain;
        this.commandName        = promise.script.commandName;
        this.requestJSONString  = promise.script.requestJSONString;
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // java.lang.Object, Cloneable, Comarable Methods
    // ********************************************************************************************
    // ********************************************************************************************


    public String toString()
    {
        final String ret =
            "BrowserError Received:\n" +
            "{\n" +
            "    Code:    " + this.code + '\n' +
            "    Message: " + this.message + '\n';

        if (this.domain == null) return ret + '}';

        return ret + 
            "    Domain:  " + this.domain.getPackageName() + '\n' +
            "    Command: " + this.commandName + 
            '}';
    }

    public int hashCode()
    { return this.code + this.message.hashCode(); }

    public boolean equals(Object other)
    {
        if (this == other) return true;
        if (other == null) return false;

        if (this.getClass() != other.getClass()) return false;

        final BrowserError o = (BrowserError) other;

        return
                (this.code == o.code)
            &&  Objects.equals(this.message, o.message)
            &&  Objects.equals(this.domain, o.domain)
            &&  Objects.equals(this.commandName, o.commandName);
    }

    public int compareTo(BrowserError error)
    {
        if (this.code != error.code)
            return this.code - error.code;

        return this.message.compareTo(error.message);
    }
}