1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.schemagen.json.impl.builder;
7   
8   import com.fasterxml.jackson.databind.node.ArrayNode;
9   import com.fasterxml.jackson.databind.node.ObjectNode;
10  
11  import gov.nist.secauto.metaschema.core.model.IChoiceGroupInstance;
12  import gov.nist.secauto.metaschema.core.model.IGroupable;
13  import gov.nist.secauto.metaschema.core.model.IModelDefinition;
14  import gov.nist.secauto.metaschema.core.model.IModelInstance;
15  import gov.nist.secauto.metaschema.core.model.INamedModelInstanceAbsolute;
16  import gov.nist.secauto.metaschema.core.model.INamedModelInstanceGrouped;
17  import gov.nist.secauto.metaschema.core.model.JsonGroupAsBehavior;
18  import gov.nist.secauto.metaschema.schemagen.json.IDataTypeJsonSchema;
19  import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema;
20  import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey;
21  import gov.nist.secauto.metaschema.schemagen.json.IDefinitionJsonSchema;
22  import gov.nist.secauto.metaschema.schemagen.json.IJsonGenerationState;
23  
24  import java.util.List;
25  import java.util.Map;
26  
27  import edu.umd.cs.findbugs.annotations.NonNull;
28  import edu.umd.cs.findbugs.annotations.Nullable;
29  
30  public interface IModelInstanceBuilder<T extends IModelInstanceBuilder<T>> extends IBuilder<T> {
31    @NonNull
32    T addItemType(@NonNull INamedModelInstanceGrouped itemType);
33  
34    @NonNull
35    T addItemType(@NonNull INamedModelInstanceAbsolute itemType);
36  
37    @NonNull
38    T minItems(int min);
39  
40    @NonNull
41    T maxItems(int max);
42  
43    @NonNull
44    List<IType> getTypes();
45  
46    int getMinOccurrence();
47  
48    int getMaxOccurrence();
49  
50    interface IType {
51      @Nullable
52      IDefineableJsonSchema getJsonKeyFlagSchema(@NonNull IJsonGenerationState state);
53  
54      @Nullable
55      IDataTypeJsonSchema getJsonKeyDataTypeSchema(@NonNull IJsonGenerationState state);
56  
57      @NonNull
58      IDefinitionJsonSchema<IModelDefinition> getJsonSchema(@NonNull IJsonGenerationState state);
59  
60      void build(
61          @NonNull ArrayNode anyOf,
62          @NonNull IJsonGenerationState state);
63  
64      void build(
65          @NonNull ObjectNode object,
66          @NonNull IJsonGenerationState state);
67  
68      default void gatherDefinitions(
69          @NonNull Map<IKey, IDefinitionJsonSchema<?>> gatheredDefinitions,
70          @NonNull IJsonGenerationState state) {
71        IDefinitionJsonSchema<IModelDefinition> schema = getJsonSchema(state);
72        schema.gatherDefinitions(gatheredDefinitions, state);
73      }
74    }
75  
76    @NonNull
77    static <I extends IModelInstance & IGroupable> IModelInstanceBuilder<?> builder(@NonNull I instance) {
78      IModelInstanceBuilder<?> builder;
79  
80      if (instance instanceof INamedModelInstanceAbsolute) {
81        INamedModelInstanceAbsolute named = (INamedModelInstanceAbsolute) instance;
82        builder = newCollectionBuilder(named);
83        builder.addItemType(named);
84      } else if (instance instanceof IChoiceGroupInstance) {
85        IChoiceGroupInstance choice = (IChoiceGroupInstance) instance;
86        builder = newCollectionBuilder(choice);
87        for (INamedModelInstanceGrouped groupedInstance : choice.getNamedModelInstances()) {
88          assert groupedInstance != null;
89          builder.addItemType(groupedInstance);
90        }
91      } else {
92        throw new UnsupportedOperationException(
93            "Unsupported named model instance type: " + instance.getClass().getName());
94      }
95      return builder;
96    }
97  
98    @NonNull
99    static IModelInstanceBuilder<?> newCollectionBuilder(@NonNull IGroupable groupable) {
100     JsonGroupAsBehavior behavior = groupable.getJsonGroupAsBehavior();
101     IModelInstanceBuilder<?> retval;
102     switch (behavior) {
103     case LIST:
104       retval = new ArrayBuilder();
105       break;
106     case SINGLETON_OR_LIST:
107       retval = new SingletonOrListBuilder();
108       break;
109     case KEYED:
110       retval = new KeyedObjectBuilder();
111       break;
112     case NONE:
113       retval = new SingletonBuilder();
114       break;
115     default:
116       throw new UnsupportedOperationException(
117           String.format("Unsupported group-as in-json binding '%s'.", behavior));
118     }
119 
120     retval.minItems(groupable.getMinOccurs());
121     retval.maxItems(groupable.getMaxOccurs());
122     return retval;
123   }
124 }