001package Torello.Browser.JsonAST;
002
003import Torello.JavaDoc.Annotations.JDHeaderBackgroundImg;
004
005import Torello.Java.ReadOnly.ReadOnlyList;
006import Torello.Java.ReadOnly.ReadOnlySet;
007
008import Torello.Java.Additional.Ret2;
009import Torello.Java.Additional.Ret4;
010
011import Torello.Java.StrCSV;
012
013import javax.json.JsonObject;
014import javax.json.JsonArray;
015
016/**
017 * Root ancestor for all CDP JSON entities parsed from the protocol specs
018 * (<CODE>browser_protocol&#46;json</CODE> and <CODE>js_protocol&#46;json</CODE>).
019 * 
020 * <EMBED CLASS='external-html' DATA-FILE-ID=AST_TREES>
021 * <EMBED CLASS="external-html" DATA-FILE-ID=Entity>
022 * 
023 * @see TCE
024 * @see PPR
025 * @see PropName
026 * @see TypeProp
027 */
028@JDHeaderBackgroundImg(EmbedTagFileID="AST_NODES_JDHBI")
029public abstract class Entity implements java.io.Serializable, Comparable<Entity>
030{
031    // ********************************************************************************************
032    // ********************************************************************************************
033    // STATIC FINAL FIELDS
034    // ********************************************************************************************
035    // ********************************************************************************************
036
037
038    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
039    protected static final long serialVersionUID = 1;
040
041
042    // ********************************************************************************************
043    // ********************************************************************************************
044    // Constant & Final Instance-Fields (Set by the Constructor)
045    // ********************************************************************************************
046    // ********************************************************************************************
047
048
049    /**
050     * Monotonic ID for this CDP entity used by {@code equals} and {@code hashCode}.
051     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.id>
052     */
053    public final int id = IDManager.nextID();
054
055    /**
056     * CDP domain that owns this entity (for example, {@code 'Network'} or {@code 'DOM'}).
057     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.ownerDomain>
058     */
059    public final Domain ownerDomain;
060
061    /**
062     * Canonical CDP name for this entity.
063     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.name>
064     */
065    public final String name;
066
067    /**
068     * Human-readable description of the CDP entity as specified in the protocol, by Google.
069     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.description>
070     */
071    public final String description;
072
073    /**
074     * There are only two concrete subclasses of {@code Entity}: {@link PPR} and {@TCE}.
075     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.whichEntity>
076     */
077    public final WhichEntity whichEntity;
078
079    /**
080     * List of all {@code JsonObject} property keys for this CDP item, as parsed from the 
081     * {@code JsonObjet} from which this {@code Entity} instance was extracted.
082     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.propNames>
083     */
084    public final ReadOnlyList<PropName> propNames;
085
086    /**
087     * The {@link JsonObject} {@code "type"} Property for this item as a strict enum.
088     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.typeProp>
089     */
090    public final TypeProp typeProp;
091
092    /**
093     * Additional type, used when the {@link #typeProp} equals {@link TypeProp#ARRAY}.
094     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.arrItemsTypeProp>
095     */
096    public final TypeProp arrItemsTypeProp;
097
098    /**
099     * True if this CDP item is optional.
100     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.optional>
101     */
102    public final boolean optional;
103
104    /**
105     * True if this CDP item is marked experimental.
106     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.experimental>
107     */
108    public final boolean experimental;
109
110    /**
111     * True if this CDP item is marked deprecated.
112     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.deprecated>
113     */
114    public final boolean deprecated;
115
116    /**
117     * Allowed enumeration {@code String} values for this CDP item.
118     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.enumVals>
119     */
120    public final ReadOnlyList<String> enumVals;
121
122    /**
123     * Comma-separated rendering of {@link #enumVals}, used to facilitate printing summaries.
124     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.enumValsStr>
125     */
126    public final String enumValsStr;
127
128    /**
129     * Every {@code Entity} instance is parsed from a {@link JsonArray}; this is the array index.
130     * <EMBED CLASS='external-html' DATA-FILE-ID=Entity.index>
131     */
132    public final int index;
133
134
135    // ********************************************************************************************
136    // ********************************************************************************************
137    // Constructor
138    // ********************************************************************************************
139    // ********************************************************************************************
140
141
142    Entity(
143            final Domain                ownerDomain,
144            final WhichEntity           which,
145            final JsonObject            jo,
146            final int                   index,
147            final ReadOnlySet<String>   extraAllowedJsonPropNames
148        )
149    {
150        this.ownerDomain    = ownerDomain;
151        this.whichEntity    = which;
152        this.index          = index;
153
154
155        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
156        // The complete list of Json-Properties contained by this object (at the top level)
157        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
158        // 
159        // This is used inside the "exception location summry".  This must be done first..
160        this.name = Helper$Name.getName(this, jo);
161
162
163        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
164        // JsonException - Expected Keys
165        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
166        // 
167        // Make sure we have looked at all the elements in the JsonObject
168        // If there are any we missed, throw an exception.
169
170        Helper$CheckKeys.entityCheck(this, jo, extraAllowedJsonPropNames);
171
172
173        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
174        // The complete list of Json-Properties contained by this object (at the top level)
175        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
176
177        this.propNames = Helper$Misc.getPropNames(jo);
178
179
180        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
181        // typeProp & arrItemsTypeProp
182        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
183
184        Ret2<TypeProp, TypeProp> ret2 = Helper$TypeProps.get(jo);
185
186        this.typeProp           = ret2.a;
187        this.arrItemsTypeProp   = ret2.b;
188
189
190        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
191        // this.description & FLAGS
192        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
193
194        final Ret4<String, Boolean, Boolean, Boolean> ret4 = Helper$Misc.getDescAndFlags(jo);
195
196        this.description    = ret4.a;   
197        this.optional       = ret4.b;
198        this.experimental   = ret4.c;
199        this.deprecated     = ret4.d;
200
201
202        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
203        // An 'enum' property in the JsonObject / Entity
204        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
205
206        this.enumVals = Helper$Enum.getEnumPropertyOrNull(this, jo);
207
208        this.enumValsStr = (enumVals == null)
209            ? null
210            : StrCSV.toCSV(enumVals, (String s) -> ("\"" + s + "\""), true, null);
211    }
212
213    /** Helper method, used to print this node's vital information. */
214    public final String exceptionLocationSummary()
215    {
216        return
217            "Node-Name:       [" + this.name + "]\n" +
218            "Owner-Domain:    [" + this.ownerDomain.name + "]\n" +
219            "WhichEntity:     [" + this.whichEntity + "]\n" +
220            "Class-Name:      [" + this.getClass().getSimpleName() + "]\n" +
221            "JsonArray Index: [" + this.index + "]\n";
222    }
223
224
225    // The Type-Parameter "T" is a lesser-known trick to get around a (somewhat glaring) JDK / 
226    // 'javac' bug.  Initializing final variables mandates that all Code-Execution Paths assign 
227    // some value to a final variable!  This is required either inside of a constructor, and also
228    // for local final variables too!  However, if one Code Execution Path ends with a method that
229    // is clearly guaranteed to throw an exception - as below - then 'javac' will flag an error 
230    // saying that "variable [XXX] might not have been initialized."
231    // 
232    // Place the word "throw" in front of the call to this method, and it will prevent that
233    // complaint.
234
235    final <T extends Throwable> T verifyThrow(final String message)
236    {
237        throw new ASTError
238            (message + '\n' + this.toString() + '\n' + this.exceptionLocationSummary());
239    }
240
241
242    // ********************************************************************************************
243    // ********************************************************************************************
244    // Comparable, Object
245    // ********************************************************************************************
246    // ********************************************************************************************
247
248
249    /** Uses several pieces of information for generating a comparison value. */
250    public final int compareTo(final Entity other)
251    {
252        if (this == other) return 0;
253        if (other == null) return 1;
254
255        if (this.ownerDomain.ownerAPI != other.ownerDomain.ownerAPI)
256            return this.ownerDomain.ownerAPI.name.compareTo
257                (other.ownerDomain.ownerAPI.name);
258
259        if (this.ownerDomain != other.ownerDomain)
260            return this.ownerDomain.name.compareTo(other.ownerDomain.name);
261
262        if (this.whichEntity != other.whichEntity)
263            return this.whichEntity.compareTo(other.whichEntity);
264
265        int c = this.name.compareTo(other.name);
266
267        return (c != 0)
268            ? c
269            : Integer.compare(this.hashCode(), other.hashCode());
270    }
271
272    /** Returns the {@link #id} as a hash value. */
273    public final int hashCode()
274    { return id; }
275
276    /** Checks that this {@link #id} is equal to {@code other.id}. */
277    public final boolean equals(final Object other)
278    {
279        if (other == null)              return false;
280        if (!(other instanceof Entity)) return false;
281        return this.id == ((Entity) other).id;
282    }
283}