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 package gov.nist.secauto.metaschema.schemagen.json.schema;
28
29 import com.fasterxml.jackson.databind.node.ArrayNode;
30 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
31 import com.fasterxml.jackson.databind.node.ObjectNode;
32
33 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
34 import gov.nist.secauto.metaschema.core.model.IChoiceInstance;
35 import gov.nist.secauto.metaschema.core.model.IFlagInstance;
36 import gov.nist.secauto.metaschema.core.model.IModelInstance;
37 import gov.nist.secauto.metaschema.core.model.INamedModelInstance;
38 import gov.nist.secauto.metaschema.core.model.ModelType;
39 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
40 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
41 import gov.nist.secauto.metaschema.schemagen.FlagInstanceFilter;
42 import gov.nist.secauto.metaschema.schemagen.json.impl.JsonGenerationState;
43 import gov.nist.secauto.metaschema.schemagen.json.property.FlagInstanceJsonProperty;
44 import gov.nist.secauto.metaschema.schemagen.json.property.IJsonProperty.PropertyCollection;
45 import gov.nist.secauto.metaschema.schemagen.json.property.INamedModelInstanceJsonProperty;
46
47 import java.io.IOException;
48 import java.util.Collection;
49 import java.util.LinkedList;
50 import java.util.List;
51
52 import edu.umd.cs.findbugs.annotations.NonNull;
53
54 public class AssemblyDefinitionJsonSchema
55 extends AbstractDefinitionJsonSchema<IAssemblyDefinition> {
56
57 public AssemblyDefinitionJsonSchema(
58 @NonNull IAssemblyDefinition definition) {
59 super(definition);
60 }
61
62 @Override
63 public void resolveSubSchemas(JsonGenerationState state) {
64 for (IFlagInstance instance : getDefinition().getFlagInstances()) {
65 state.getSchema(instance.getDefinition());
66 }
67
68 for (INamedModelInstance instance : getDefinition().getNamedModelInstances()) {
69 state.getSchema(instance.getDefinition());
70 }
71 }
72
73 @Override
74 protected void generateBody(JsonGenerationState state, ObjectNode obj) throws IOException {
75 IAssemblyDefinition definition = getDefinition();
76
77 obj.put("type", "object");
78
79
80 IFlagInstance jsonKeyFlag = definition.getJsonKeyFlagInstance();
81 Collection<? extends IFlagInstance> flags
82 = FlagInstanceFilter.filterFlags(definition.getFlagInstances(), jsonKeyFlag);
83
84 PropertyCollection properties = new PropertyCollection();
85
86
87 for (IFlagInstance flag : flags) {
88 assert flag != null;
89 new FlagInstanceJsonProperty(flag).generateProperty(properties, state);
90 }
91
92 Collection<? extends INamedModelInstance> instances = definition.getNamedModelInstances();
93 for (INamedModelInstance instance : instances) {
94 assert instance != null;
95 INamedModelInstanceJsonProperty.newProperty(instance)
96 .generateProperty(properties, state);
97 }
98
99 Collection<? extends IChoiceInstance> choices = definition.getChoiceInstances();
100 if (choices.isEmpty()) {
101 properties.generate(obj);
102
103 obj.put("additionalProperties", false);
104 } else {
105 generateChoices(choices, properties, obj, state);
106 }
107 }
108
109 protected void generateChoices(
110 @NonNull Collection<? extends IChoiceInstance> choices,
111 @NonNull PropertyCollection properties,
112 @NonNull ObjectNode definitionNode,
113 @NonNull JsonGenerationState state) throws IOException {
114 List<PropertyCollection> propertyChoices = CollectionUtil.singletonList(properties);
115 propertyChoices = explodeChoices(choices, propertyChoices, state);
116
117 if (propertyChoices.size() == 1) {
118 propertyChoices.iterator().next().generate(definitionNode);
119 } else if (propertyChoices.size() > 1) {
120 ArrayNode anyOfdNode = ObjectUtils.notNull(JsonNodeFactory.instance.arrayNode());
121 for (PropertyCollection propertyChoice : propertyChoices) {
122 ObjectNode choiceDefinitionNode = ObjectUtils.notNull(JsonNodeFactory.instance.objectNode());
123 propertyChoice.generate(choiceDefinitionNode);
124 choiceDefinitionNode.put("additionalProperties", false);
125 anyOfdNode.add(choiceDefinitionNode);
126 }
127 definitionNode.set("anyOf", anyOfdNode);
128 }
129 }
130
131 protected List<PropertyCollection> explodeChoices(
132 @NonNull Collection<? extends IChoiceInstance> choices,
133 @NonNull List<PropertyCollection> propertyChoices,
134 @NonNull JsonGenerationState state) throws IOException {
135
136 List<PropertyCollection> retval = propertyChoices;
137
138 for (IChoiceInstance choice : choices) {
139 List<PropertyCollection> newRetval = new LinkedList<>();
140 for (IModelInstance optionInstance : choice.getModelInstances()) {
141 if (ModelType.CHOICE.equals(optionInstance.getModelType())) {
142
143 newRetval.addAll(explodeChoices(
144 CollectionUtil.singleton((IChoiceInstance) optionInstance),
145 retval,
146 state));
147 } else {
148
149 for (PropertyCollection oldInstanceProperties : retval) {
150 @SuppressWarnings("null")
151 @NonNull PropertyCollection newInstanceProperties = oldInstanceProperties.copy();
152
153
154 INamedModelInstanceJsonProperty.newProperty((INamedModelInstance) optionInstance)
155 .generateProperty(newInstanceProperties, state);
156
157 newRetval.add(newInstanceProperties);
158 }
159 }
160 }
161 retval = newRetval;
162 }
163 return retval;
164 }
165 }