1
2
3
4
5
6 package gov.nist.secauto.metaschema.schemagen.json.impl;
7
8 import com.fasterxml.jackson.core.JsonGenerator;
9 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
10 import com.fasterxml.jackson.databind.node.ObjectNode;
11
12 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
13 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
14 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
15 import gov.nist.secauto.metaschema.core.model.IDefinition;
16 import gov.nist.secauto.metaschema.core.model.IFieldDefinition;
17 import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
18 import gov.nist.secauto.metaschema.core.model.IModule;
19 import gov.nist.secauto.metaschema.core.model.IValuedDefinition;
20 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
21 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
22 import gov.nist.secauto.metaschema.schemagen.AbstractGenerationState;
23 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
24 import gov.nist.secauto.metaschema.schemagen.json.IDataTypeJsonSchema;
25 import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey;
26 import gov.nist.secauto.metaschema.schemagen.json.IDefinitionJsonSchema;
27 import gov.nist.secauto.metaschema.schemagen.json.IJsonGenerationState;
28
29 import java.io.IOException;
30 import java.util.Comparator;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap;
35
36 import edu.umd.cs.findbugs.annotations.NonNull;
37 import edu.umd.cs.findbugs.annotations.Nullable;
38
39 public class JsonGenerationState
40 extends AbstractGenerationState<JsonGenerator, JsonDatatypeManager>
41 implements IJsonGenerationState {
42
43 @NonNull
44 private final JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(true);
45 @NonNull
46 private final Map<IKey, IDefinitionJsonSchema<?>> schemaDefinitions = new HashMap<>();
47 @NonNull
48 private final Map<IValuedDefinition, IDataTypeJsonSchema> definitionValueToDataTypeSchemaMap
49 = new ConcurrentHashMap<>();
50 @NonNull
51 private final Map<IDataTypeAdapter<?>, IDataTypeJsonSchema> dataTypeToSchemaMap = new ConcurrentHashMap<>();
52
53 public JsonGenerationState(
54 @NonNull IModule module,
55 @NonNull JsonGenerator writer,
56 @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration) {
57 super(module, writer, configuration, new JsonDatatypeManager());
58
59
60
61
62
63
64
65
66
67
68
69
70
71 }
72
73 @Override
74 @NonNull
75 public <DEF extends IDefinition> IDefinitionJsonSchema<DEF> getSchema(@NonNull IKey key) {
76 IDefinitionJsonSchema<?> retval = getDefinitionSchema(key, this);
77 return ObjectUtils.asType(ObjectUtils.requireNonNull(retval));
78 }
79
80 @Override
81 @NonNull
82 public IDataTypeJsonSchema getSchema(@NonNull IDataTypeAdapter<?> datatype) {
83 IDataTypeJsonSchema retval = dataTypeToSchemaMap.get(datatype);
84 if (retval == null) {
85 retval = new DataTypeJsonSchema(
86 getDatatypeManager().getTypeNameForDatatype(datatype),
87 datatype);
88 dataTypeToSchemaMap.put(datatype, retval);
89 }
90 return retval;
91 }
92
93
94
95
96
97
98
99
100 private IDefinitionJsonSchema<?> getDefinitionSchema(
101 @NonNull IKey key,
102 @NonNull IJsonGenerationState state) {
103 synchronized (schemaDefinitions) {
104 return schemaDefinitions.computeIfAbsent(key, (k) -> {
105 IDefinitionJsonSchema<?> retval = newJsonSchema(
106 k.getDefinition(),
107 k.getJsonKeyFlagName(),
108 k.getDiscriminatorProperty(),
109 k.getDiscriminatorValue(),
110 state);
111 assert key.equals(retval.getKey());
112 return retval;
113 });
114 }
115 }
116
117 @Override
118 public boolean isDefinitionRegistered(IDefinitionJsonSchema<?> schema) {
119 return schemaDefinitions.containsKey(schema.getKey());
120 }
121
122 @Override
123 public void registerDefinitionSchema(IDefinitionJsonSchema<?> schema) {
124 IDefinitionJsonSchema<?> old = schemaDefinitions.put(schema.getKey(), schema);
125 assert old == null;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 @NonNull
145 private static IDefinitionJsonSchema<?> newJsonSchema(
146 @NonNull IDefinition definition,
147 @Nullable String jsonKeyFlagName,
148 @Nullable String discriminatorProperty,
149 @Nullable String discriminatorValue,
150 @NonNull IJsonGenerationState state) {
151 IDefinitionJsonSchema<?> retval;
152 if (definition instanceof IFlagDefinition) {
153 retval = new FlagDefinitionJsonSchema((IFlagDefinition) definition, state);
154 } else if (definition instanceof IAssemblyDefinition) {
155 retval = new AssemblyDefinitionJsonSchema(
156 (IAssemblyDefinition) definition,
157 jsonKeyFlagName,
158 discriminatorProperty,
159 discriminatorValue,
160 state);
161 } else if (definition instanceof IFieldDefinition) {
162 retval = new FieldDefinitionJsonSchema(
163 (IFieldDefinition) definition,
164 jsonKeyFlagName,
165 discriminatorProperty,
166 discriminatorValue,
167 state);
168 } else {
169 throw new IllegalArgumentException("Unsupported definition type" + definition.getClass().getName());
170 }
171 return retval;
172 }
173
174 public ObjectNode generateDefinitions() {
175 @NonNull Map<IKey, IDefinitionJsonSchema<?>> gatheredDefinitions = new HashMap<>();
176
177 getMetaschemaIndex().getDefinitions().stream()
178 .filter(entry -> entry.isRoot())
179 .map(entry -> entry.getDefinition())
180 .forEachOrdered(def -> {
181 IDefinitionJsonSchema<?> definitionSchema = getSchema(IKey.of(def));
182 assert definitionSchema != null;
183 definitionSchema.gatherDefinitions(gatheredDefinitions, this);
184 });
185
186 ObjectNode definitionsObject = ObjectUtils.notNull(JsonNodeFactory.instance.objectNode());
187
188 gatheredDefinitions.values().stream()
189 .filter(schema -> !isInline(schema.getDefinition()))
190 .sorted(Comparator.comparing(schema -> schema.getDefinitionName(this)))
191 .forEachOrdered(schema -> {
192 schema.generateDefinition(this, definitionsObject);
193 });
194
195 getDatatypeManager().generateDatatypes(definitionsObject);
196
197 return definitionsObject;
198 }
199
200 @Override
201 public JsonNodeFactory getJsonNodeFactory() {
202 return jsonNodeFactory;
203 }
204
205 @Override
206 @NonNull
207 public IDataTypeJsonSchema getDataTypeSchemaForDefinition(@NonNull IValuedDefinition definition) {
208 IDataTypeJsonSchema retval = definitionValueToDataTypeSchemaMap.get(definition);
209 if (retval == null) {
210 AllowedValueCollection allowedValuesCollection = getContextIndependentEnumeratedValues(definition);
211 List<IAllowedValue> allowedValues = allowedValuesCollection.getValues();
212
213 IDataTypeAdapter<?> dataTypeAdapter = definition.getJavaTypeAdapter();
214
215
216 retval = getSchema(dataTypeAdapter);
217 if (!allowedValues.isEmpty()) {
218
219 retval = new DataTypeRestrictionDefinitionJsonSchema(definition, allowedValuesCollection);
220 }
221 definitionValueToDataTypeSchemaMap.put(definition, retval);
222 }
223 return retval;
224 }
225
226 @SuppressWarnings("resource")
227 public void writeStartObject() throws IOException {
228 getWriter().writeStartObject();
229 }
230
231 @SuppressWarnings("resource")
232 public void writeEndObject() throws IOException {
233 getWriter().writeEndObject();
234 }
235
236 @SuppressWarnings("resource")
237 public void writeField(String fieldName, String value) throws IOException {
238 getWriter().writeStringField(fieldName, value);
239
240 }
241
242 @SuppressWarnings("resource")
243 public void writeField(String fieldName, ObjectNode obj) throws IOException {
244 JsonGenerator writer = getWriter();
245
246 writer.writeFieldName(fieldName);
247 writer.writeTree(obj);
248 }
249
250 @Override
251 public void flushWriter() throws IOException {
252 getWriter().flush();
253 }
254
255 }