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