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.IAssemblyDefinition;
11  import gov.nist.secauto.metaschema.core.model.IAssemblyInstanceGrouped;
12  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
13  
14  import java.util.ArrayList;
15  import java.util.List;
16  import java.util.Set;
17  import java.util.stream.Collectors;
18  import java.util.stream.Stream;
19  
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  import nl.talsmasoftware.lazy4j.Lazy;
22  
23  /**
24   * Supports generation of a JSON schema based on a Metaschema
25   * {@link IAssemblyInstanceGrouped}, which can be generated inline or as a JSON
26   * schema definition.
27   */
28  public class JsonSchemaPropertyGroupedAssembly
29      extends AbstractJsonSchemaPropertyGrouped<IAssemblyInstanceGrouped>
30      implements IJsonSchemaDefinitionAssembly {
31    private final Lazy<List<JsonSchemaHelper.Choice>> choices;
32  
33    /**
34     * Construct a new JSON schema property.
35     *
36     * @param instance
37     *          the instance to construct the property for
38     * @param state
39     *          the JSON generation state used to get JSON schema information
40     */
41    public JsonSchemaPropertyGroupedAssembly(
42        @NonNull IAssemblyInstanceGrouped instance,
43        @NonNull IJsonGenerationState state) {
44      super(instance, state);
45      this.choices = Lazy.lazy(() -> {
46        List<IJsonSchemaPropertyFlag> flagProperties = getFlagProperties();
47        List<IJsonSchemaPropertyNamed> modelProperties
48            = JsonSchemaHelper.buildModelProperties(instance.getDefinition(), state);
49  
50        List<IJsonSchemaPropertyNamed> properties = new ArrayList<>(flagProperties.size() + modelProperties.size());
51        properties.add(new DiscriminatorProperty());
52        properties.addAll(flagProperties);
53        properties.addAll(modelProperties);
54  
55        JsonSchemaHelper.Choice baseChoice = new JsonSchemaHelper.Choice(properties);
56        return JsonSchemaHelper.explodeChoices(baseChoice, instance.getDefinition().getChoiceInstances(), state)
57            .collect(Collectors.toUnmodifiableList());
58      });
59    }
60  
61    @Override
62    public IAssemblyDefinition getDefinition() {
63      return getInstance().getDefinition();
64    }
65  
66    @Override
67    public List<JsonSchemaHelper.Choice> getChoices() {
68      return ObjectUtils.notNull(choices.get());
69    }
70  
71    @Override
72    public Stream<IJsonSchemaDefinable> collectDefinitions(
73        Set<IJsonSchemaDefinitionAssembly> visited,
74        IJsonGenerationState state) {
75      Set<IJsonSchemaDefinitionAssembly> myVisited
76          = ObjectUtils.notNull(Stream.concat(visited.stream(), Stream.of(this))
77              .collect(Collectors.toUnmodifiableSet()));
78  
79      assert visited.contains(this) || visited.stream()
80          .noneMatch(schema -> schema.getDefinition().equals(getDefinition()));
81  
82      return ObjectUtils.notNull(visited.contains(this)
83          ? Stream.of(this)
84          : Stream.concat(
85              super.collectDefinitions(myVisited, state),
86              choices.get().stream()
87                  .flatMap(choice -> choice.getCombinations().stream()
88                      .flatMap(property -> property.collectDefinitions(myVisited, state)))));
89    }
90  
91    @Override
92    public void generateBody(ObjectNode node, IJsonGenerationState state) {
93      JsonSchemaHelper.generateAssemblyBody(this, node, state);
94    }
95  }