1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.schemagen.json.impl;
7   
8   import com.fasterxml.jackson.databind.node.ArrayNode;
9   import com.fasterxml.jackson.databind.node.JsonNodeFactory;
10  import com.fasterxml.jackson.databind.node.ObjectNode;
11  
12  import gov.nist.secauto.metaschema.core.model.IInstance;
13  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
14  import gov.nist.secauto.metaschema.schemagen.SchemaGenerationException;
15  import gov.nist.secauto.metaschema.schemagen.json.IDefineableJsonSchema.IKey;
16  import gov.nist.secauto.metaschema.schemagen.json.IDefinitionJsonSchema;
17  import gov.nist.secauto.metaschema.schemagen.json.IJsonGenerationState;
18  
19  import java.util.Collections;
20  import java.util.LinkedHashMap;
21  import java.util.LinkedHashSet;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import edu.umd.cs.findbugs.annotations.NonNull;
26  
27  public interface IJsonProperty<I extends IInstance> {
28    @NonNull
29    I getInstance();
30  
31    @NonNull
32    String getName();
33  
34    boolean isRequired();
35  
36    void gatherDefinitions(
37        @NonNull Map<IKey, IDefinitionJsonSchema<?>> gatheredDefinitions,
38        @NonNull IJsonGenerationState state);
39  
40    /**
41     * Generate the schema type.
42     *
43     * @param properties
44     *          the containing property context to add the property to
45     * @param state
46     *          the schema generation state used for context and writing
47     * @param jsonKeyFlagName
48     *          the name of the flag to use as the JSON key, or @{code null} if no
49     *          flag is used as the JSON key
50     * @param discriminator
51     *          the name to use as the choice group discriminator, or @{code null}
52     *          if no choice group discriminator is used
53     * @throws SchemaGenerationException
54     *           if an error occurred while writing the type
55     */
56    void generateProperty(
57        @NonNull PropertyCollection properties,
58        @NonNull IJsonGenerationState state);
59  
60    class PropertyCollection {
61      private final Map<String, ObjectNode> properties;
62      private final Set<String> required;
63  
64      public PropertyCollection() {
65        this(new LinkedHashMap<>(), new LinkedHashSet<>());
66      }
67  
68      protected PropertyCollection(@NonNull Map<String, ObjectNode> properties, @NonNull Set<String> required) {
69        this.properties = properties;
70        this.required = required;
71      }
72  
73      public Map<String, ObjectNode> getProperties() {
74        return Collections.unmodifiableMap(properties);
75      }
76  
77      public Set<String> getRequired() {
78        return Collections.unmodifiableSet(required);
79      }
80  
81      public void addProperty(@NonNull String name, @NonNull ObjectNode def) {
82        properties.put(name, def);
83      }
84  
85      public void addRequired(@NonNull String name) {
86        required.add(name);
87      }
88  
89      public PropertyCollection copy() {
90        return new PropertyCollection(new LinkedHashMap<>(properties), new LinkedHashSet<>(required));
91      }
92  
93      public void generate(@NonNull ObjectNode obj) {
94        if (!properties.isEmpty()) {
95          ObjectNode propertiesNode = ObjectUtils.notNull(JsonNodeFactory.instance.objectNode());
96          for (Map.Entry<String, ObjectNode> entry : properties.entrySet()) {
97            propertiesNode.set(entry.getKey(), entry.getValue());
98          }
99          obj.set("properties", propertiesNode);
100 
101         if (!required.isEmpty()) {
102           ArrayNode requiredNode = ObjectUtils.notNull(JsonNodeFactory.instance.arrayNode());
103           for (String requiredProperty : required) {
104             requiredNode.add(requiredProperty);
105           }
106           obj.set("required", requiredNode);
107         }
108       }
109     }
110   }
111 }