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.ObjectNode;
9   
10  import gov.nist.secauto.metaschema.core.model.IFlagInstance;
11  import gov.nist.secauto.metaschema.core.model.IModelDefinition;
12  import gov.nist.secauto.metaschema.core.model.INamedModelInstanceGrouped;
13  import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
14  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
15  
16  import java.util.List;
17  import java.util.Set;
18  import java.util.stream.Stream;
19  
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  import nl.talsmasoftware.lazy4j.Lazy;
22  
23  /**
24   * A JSON schema for a given Metaschema-based definition instance, that is part
25   * of a choice group, which is part of a larger JSON schema.
26   *
27   * @param <I>
28   *          the Java type of the Metaschema definition instance
29   */
30  public abstract class AbstractJsonSchemaPropertyGrouped<I extends INamedModelInstanceGrouped>
31      extends AbstractJsonSchemaProperty<I>
32      implements IJsonSchemaPropertyGrouped {
33    @NonNull
34    private final Lazy<String> definitionName;
35    @NonNull
36    private final List<IJsonSchemaPropertyFlag> flagProperties;
37    private final IFlagInstance jsonKey;
38  
39    /**
40     * Construct a new JSON schema property based on a Metaschema definition
41     * instance.
42     *
43     * @param instance
44     *          the Metaschema definition instance
45     * @param state
46     *          the generation state used to generate this JSON schema
47     */
48    protected AbstractJsonSchemaPropertyGrouped(@NonNull I instance, @NonNull IJsonGenerationState state) {
49      super(instance);
50      this.definitionName = ObjectUtils.notNull(Lazy.lazy(() -> getDefinitionName(state)));
51      this.jsonKey = instance.getJsonKey();
52  
53      IEnhancedQName jsonKeyName = this.jsonKey == null ? null : this.jsonKey.getQName();
54      this.flagProperties
55          = JsonSchemaHelper.buildFlagProperties(instance.getDefinition(), jsonKeyName, state);
56    }
57  
58    @Override
59    public final List<IJsonSchemaPropertyFlag> getFlagProperties() {
60      return flagProperties;
61    }
62  
63    @Override
64    public IFlagInstance getJsonKeyFlag() {
65      return jsonKey;
66    }
67  
68    @Override
69    public String getDefinitionName() {
70      return ObjectUtils.notNull(definitionName.get());
71    }
72  
73    private String getDefinitionName(IJsonGenerationState state) {
74      INamedModelInstanceGrouped instance = getInstance();
75      IModelDefinition definition = instance.getDefinition();
76  
77      String discriminatorProperty = instance.getParentContainer().getJsonDiscriminatorProperty();
78      String discriminatorValue = instance.getEffectiveDisciminatorValue();
79  
80      IFlagInstance jsonKey = getJsonKeyFlag();
81  
82      return state.generateJsonSchemaDefinitionName(
83          definition,
84          jsonKey == null ? null : jsonKey.getEffectiveName(),
85          ObjectUtils.requireNonNull(discriminatorProperty),
86          ObjectUtils.requireNonNull(discriminatorValue),
87          "Choice");
88    }
89  
90    @Override
91    public Stream<IJsonSchemaDefinable> collectDefinitions(
92        Set<IJsonSchemaDefinitionAssembly> visited,
93        IJsonGenerationState state) {
94      Stream<IJsonSchemaDefinable> retval = Stream.concat(
95          Stream.of(this),
96          getFlagProperties().stream()
97              .flatMap(property -> property.collectDefinitions(visited, state)));
98  
99      IFlagInstance jsonKeyFlag = getJsonKeyFlag();
100     if (jsonKeyFlag != null) {
101       retval = Stream.concat(retval, Stream.of(state.getFlagDefinition(jsonKeyFlag.getDefinition())));
102     }
103     return ObjectUtils.notNull(retval);
104 
105   }
106 
107   /**
108    * Represents a JSON schema property used to declare the type of a choice group
109    * object.
110    */
111   protected class DiscriminatorProperty implements IJsonSchemaPropertyNamed {
112     @Override
113     public Stream<IJsonSchemaDefinable> collectDefinitions(Set<IJsonSchemaDefinitionAssembly> visited,
114         IJsonGenerationState state) {
115       return ObjectUtils.notNull(Stream.empty());
116     }
117 
118     @Override
119     public void generate(ObjectNode node, IJsonGenerationState state) {
120       node.put("const", getInstance().getEffectiveDisciminatorValue());
121     }
122 
123     @Override
124     public String getName() {
125       return getInstance().getParentContainer().getJsonDiscriminatorProperty();
126     }
127 
128     @Override
129     public boolean isRequired() {
130       return true;
131     }
132   }
133 }