001package Torello.Browser.JsonAST;
002
003import Torello.Java.StrCSV;
004
005import Torello.Java.ReadOnly.ReadOnlySet;
006import Torello.Java.ReadOnly.ReadOnlyTreeSet;
007
008import java.util.TreeSet;
009import javax.json.JsonObject;
010
011/**
012 * There are two implementation methods of the "Check Keys" feature in this class.  The first 
013 * "Check Key Method" may be used with any of the six {@link Entity} subclasses:
014 * {@link PPR}, {@link TCE}, {@link TypeNode}, {@link CommandNode} & {@link EventNode}.
015 * 
016 * <BR /><BR />The second variant of "Check Keys" may be used on {@link JsonObject JsonObjects}
017 * which have been retrieved from the (top level) {@code "domains"} array, and are to be 
018 * extracted and parsed into instance of class {@link Domain}.
019 * 
020 * <BR /><BR />For both of these methods, all that is occuring is an "assertion statement", nothing
021 * more, nor anything less.  The assertion being promulgated is to make sure that only Json 
022 * Properties which match exactly with a well-known and well-documented sub-list of expected 
023 * property names occur.  The intention is two fold.
024 * 
025 * <BR /><BR />The first goal is to make sure to catch any unexpected changes that might ever occur
026 * in future versions of the CDP JSON spec files.  The second is to help understand, exactly, (nail
027 * down) what is and is not guaranteed to be true about a 40K line long {@code '.json'} File.  The 
028 * tests in these two methods help make obvious / elucidate what is absolutely true when parsing 
029 * these files!
030 * 
031 * <BR /><BR />That's really all this is.
032 */
033@Torello.JavaDoc.Annotations.StaticFunctional
034@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="CONSTRUCTOR_JDHBI")
035public class Helper$CheckKeys 
036{
037    private Helper$CheckKeys() { }
038
039    private static final ReadOnlySet<String> expectedEntityObjKeys = new ReadOnlyTreeSet<>(
040        String::compareTo,
041        "type",
042        "items",
043        "enum",
044        "description",
045        "optional", "experimental", "deprecated"
046    );
047
048    static void entityCheck(
049            final Entity                THIS,
050            final JsonObject            jo,
051            final ReadOnlySet<String>   subClassExpectedKeys
052        )
053    {
054        final TreeSet<String> keys = new TreeSet<>(jo.keySet());
055
056        for (final String k : expectedEntityObjKeys) keys.remove(k);
057
058        // The subclass inheriting this class will have more keys
059        for (final String k : subClassExpectedKeys) keys.remove(k);
060
061        if (keys.size() != 0) THIS.verifyThrow(
062            "Entity had unrecognized Map (JsonObject) Properties: " + 
063            StrCSV.toCSV(keys, key -> '[' + key + ']', true, null)
064        );
065    }
066
067    private static final ReadOnlySet<String> expectedDomainObjKeys = new ReadOnlyTreeSet<>(
068        String::compareTo,
069        "domain", "description",
070        "experimental", "deprecated",
071        "types", "commands", "events",
072        "dependencies"
073    );
074
075    static void domainCheck(final JsonObject jo, final String domainNamme)
076    {
077        final TreeSet<String> keys = new TreeSet<>(jo.keySet());
078
079        for (final String k : expectedDomainObjKeys) keys.remove(k);
080
081        if (keys.size() != 0) throw new ASTError(
082            "Domain JsonObjec had unrecognized Map (JsonObject) Properties: " + 
083            StrCSV.toCSV(keys, key -> '[' + key + ']', true, null)
084        );
085    }
086}