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

import Torello.Java.StrCSV;

import Torello.Java.ReadOnly.ReadOnlySet;
import Torello.Java.ReadOnly.ReadOnlyTreeSet;

import java.util.TreeSet;
import javax.json.JsonObject;

/**
 * There are two implementation methods of the "Check Keys" feature in this class.  The first 
 * "Check Key Method" may be used with any of the six {@link Entity} subclasses:
 * {@link PPR}, {@link TCE}, {@link TypeNode}, {@link CommandNode} & {@link EventNode}.
 * 
 * <BR /><BR />The second variant of "Check Keys" may be used on {@link JsonObject JsonObjects}
 * which have been retrieved from the (top level) {@code "domains"} array, and are to be 
 * extracted and parsed into instance of class {@link Domain}.
 * 
 * <BR /><BR />For both of these methods, all that is occuring is an "assertion statement", nothing
 * more, nor anything less.  The assertion being promulgated is to make sure that only Json 
 * Properties which match exactly with a well-known and well-documented sub-list of expected 
 * property names occur.  The intention is two fold.
 * 
 * <BR /><BR />The first goal is to make sure to catch any unexpected changes that might ever occur
 * in future versions of the CDP JSON spec files.  The second is to help understand, exactly, (nail
 * down) what is and is not guaranteed to be true about a 40K line long {@code '.json'} File.  The 
 * tests in these two methods help make obvious / elucidate what is absolutely true when parsing 
 * these files!
 * 
 * <BR /><BR />That's really all this is.
 */
@Torello.JavaDoc.Annotations.StaticFunctional
@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="CONSTRUCTOR_JDHBI")
public class Helper$CheckKeys 
{
    private Helper$CheckKeys() { }

    private static final ReadOnlySet<String> expectedEntityObjKeys = new ReadOnlyTreeSet<>(
        String::compareTo,
        "type",
        "items",
        "enum",
        "description",
        "optional", "experimental", "deprecated"
    );

    static void entityCheck(
            final Entity                THIS,
            final JsonObject            jo,
            final ReadOnlySet<String>   subClassExpectedKeys
        )
    {
        final TreeSet<String> keys = new TreeSet<>(jo.keySet());

        for (final String k : expectedEntityObjKeys) keys.remove(k);

        // The subclass inheriting this class will have more keys
        for (final String k : subClassExpectedKeys) keys.remove(k);

        if (keys.size() != 0) THIS.verifyThrow(
            "Entity had unrecognized Map (JsonObject) Properties: " + 
            StrCSV.toCSV(keys, key -> '[' + key + ']', true, null)
        );
    }

    private static final ReadOnlySet<String> expectedDomainObjKeys = new ReadOnlyTreeSet<>(
        String::compareTo,
        "domain", "description",
        "experimental", "deprecated",
        "types", "commands", "events",
        "dependencies"
    );

    static void domainCheck(final JsonObject jo, final String domainNamme)
    {
        final TreeSet<String> keys = new TreeSet<>(jo.keySet());

        for (final String k : expectedDomainObjKeys) keys.remove(k);

        if (keys.size() != 0) throw new ASTError(
            "Domain JsonObjec had unrecognized Map (JsonObject) Properties: " + 
            StrCSV.toCSV(keys, key -> '[' + key + ']', true, null)
        );
    }
}