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.impl;
28
29 import com.fasterxml.jackson.core.JsonGenerator;
30 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
31 import com.fasterxml.jackson.databind.node.ObjectNode;
32
33 import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
34 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
35 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
36 import gov.nist.secauto.metaschema.core.model.IDefinition;
37 import gov.nist.secauto.metaschema.core.model.IFieldDefinition;
38 import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
39 import gov.nist.secauto.metaschema.core.model.IModule;
40 import gov.nist.secauto.metaschema.core.model.IValuedDefinition;
41 import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
42 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
43 import gov.nist.secauto.metaschema.schemagen.AbstractGenerationState;
44 import gov.nist.secauto.metaschema.schemagen.SchemaGenerationFeature;
45 import gov.nist.secauto.metaschema.schemagen.json.datatype.JsonDatatypeManager;
46 import gov.nist.secauto.metaschema.schemagen.json.schema.AssemblyDefinitionJsonSchema;
47 import gov.nist.secauto.metaschema.schemagen.json.schema.DataTypeJsonSchema;
48 import gov.nist.secauto.metaschema.schemagen.json.schema.DataTypeRestrictionDefinitionJsonSchema;
49 import gov.nist.secauto.metaschema.schemagen.json.schema.FieldDefinitionJsonSchema;
50 import gov.nist.secauto.metaschema.schemagen.json.schema.FlagDefinitionJsonSchema;
51 import gov.nist.secauto.metaschema.schemagen.json.schema.IDefineableJsonSchema;
52 import gov.nist.secauto.metaschema.schemagen.json.schema.IJsonSchema;
53
54 import java.io.IOException;
55 import java.util.LinkedHashSet;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59 import java.util.concurrent.ConcurrentHashMap;
60
61 import edu.umd.cs.findbugs.annotations.NonNull;
62
63 public class JsonGenerationState
64 extends AbstractGenerationState<JsonGenerator, JsonDatatypeManager> {
65
66 @NonNull
67 private final Set<IDefineableJsonSchema> definitionSchemas = new LinkedHashSet<>();
68 @NonNull
69 private final Map<IDefinition, IJsonSchema> definitionToSchemaMap = new ConcurrentHashMap<>();
70 @NonNull
71 private final Map<IValuedDefinition, IJsonSchema> definitionValueToDataTypeSchemaMap = new ConcurrentHashMap<>();
72 @NonNull
73 private final Map<IDataTypeAdapter<?>, IJsonSchema> dataTypeToSchemaMap = new ConcurrentHashMap<>();
74
75 public JsonGenerationState(
76 @NonNull IModule module,
77 @NonNull JsonGenerator writer,
78 @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration) {
79 super(module, writer, configuration, new JsonDatatypeManager());
80 }
81
82 @NonNull
83 public IJsonSchema getDataTypeSchemaForDefinition(@NonNull IValuedDefinition definition) {
84 IJsonSchema retval = definitionValueToDataTypeSchemaMap.get(definition);
85 if (retval == null) {
86 AllowedValueCollection allowedValuesCollection = getContextIndependentEnumeratedValues(definition);
87 List<IAllowedValue> allowedValues = allowedValuesCollection.getValues();
88
89 if (allowedValues.isEmpty()) {
90
91 retval = getSchema(definition.getJavaTypeAdapter());
92 } else {
93 IDefineableJsonSchema restriction
94 = new DataTypeRestrictionDefinitionJsonSchema(definition, allowedValuesCollection);
95 registerDefinitionSchema(restriction);
96 retval = restriction;
97 }
98 definitionValueToDataTypeSchemaMap.put(definition, retval);
99 retval.resolveSubSchemas(this);
100 }
101 return retval;
102 }
103
104 @NonNull
105 public IJsonSchema getSchema(@NonNull IDefinition definition) {
106 IJsonSchema retval = definitionToSchemaMap.get(definition);
107 if (retval == null) {
108 IDefineableJsonSchema definitionSchema;
109 switch (definition.getModelType()) {
110 case ASSEMBLY:
111 definitionSchema = new AssemblyDefinitionJsonSchema((IAssemblyDefinition) definition);
112 break;
113 case FIELD:
114 definitionSchema = new FieldDefinitionJsonSchema((IFieldDefinition) definition);
115 break;
116 case FLAG:
117 definitionSchema = new FlagDefinitionJsonSchema((IFlagDefinition) definition);
118 break;
119 default:
120 throw new UnsupportedOperationException(definition.getModelType().toString());
121 }
122 definitionToSchemaMap.put(definition, definitionSchema);
123 registerDefinitionSchema(definitionSchema);
124 definitionSchema.resolveSubSchemas(this);
125 retval = definitionSchema;
126 }
127 return retval;
128 }
129
130 @NonNull
131 public IJsonSchema getSchema(@NonNull IDataTypeAdapter<?> datatype) {
132 IJsonSchema retval = dataTypeToSchemaMap.get(datatype);
133 if (retval == null) {
134 retval = new DataTypeJsonSchema(
135 getDatatypeManager().getTypeNameForDatatype(datatype),
136 datatype);
137 dataTypeToSchemaMap.put(datatype, retval);
138 }
139 return retval;
140 }
141
142 protected void registerDefinitionSchema(@NonNull IDefineableJsonSchema schema) {
143 if (schema.isDefinition(this)) {
144 synchronized (definitionSchemas) {
145 if (!definitionSchemas.contains(schema)) {
146 definitionSchemas.add(schema);
147 }
148 }
149 }
150 }
151
152 public ObjectNode generateDefinitions() {
153 ObjectNode definitionsObject = ObjectUtils.notNull(JsonNodeFactory.instance.objectNode());
154
155 for (IDefineableJsonSchema schema : definitionSchemas) {
156 schema.generateDefinition(this, definitionsObject);
157 }
158
159 getDatatypeManager().generateDatatypes(definitionsObject);
160
161 return definitionsObject;
162 }
163
164 @SuppressWarnings("resource")
165 public void writeStartObject() throws IOException {
166 getWriter().writeStartObject();
167 }
168
169 @SuppressWarnings("resource")
170 public void writeEndObject() throws IOException {
171 getWriter().writeEndObject();
172 }
173
174 @SuppressWarnings("resource")
175 public void writeField(String fieldName, String value) throws IOException {
176 getWriter().writeStringField(fieldName, value);
177
178 }
179
180 @SuppressWarnings("resource")
181 public void writeField(String fieldName, ObjectNode obj) throws IOException {
182 JsonGenerator writer = getWriter();
183
184 writer.writeFieldName(fieldName);
185 writer.writeTree(obj);
186 }
187
188 @Override
189 public void flushWriter() throws IOException {
190 getWriter().flush();
191 }
192 }