001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.schemagen;
007
008import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
009import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression;
010import gov.nist.secauto.metaschema.core.model.IDefinition;
011import gov.nist.secauto.metaschema.core.model.IModule;
012import gov.nist.secauto.metaschema.core.model.INamedInstance;
013import gov.nist.secauto.metaschema.core.model.IValuedDefinition;
014import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue;
015import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValuesConstraint;
016import gov.nist.secauto.metaschema.core.util.CollectionUtil;
017import gov.nist.secauto.metaschema.core.util.ObjectUtils;
018import gov.nist.secauto.metaschema.schemagen.datatype.IDatatypeManager;
019
020import java.util.ArrayList;
021import java.util.LinkedList;
022import java.util.List;
023
024import edu.umd.cs.findbugs.annotations.NonNull;
025import edu.umd.cs.findbugs.annotations.Nullable;
026
027public abstract class AbstractGenerationState<WRITER, DATATYPE_MANAGER extends IDatatypeManager>
028    implements IGenerationState<WRITER> {
029  @NonNull
030  private final IModule module;
031  @NonNull
032  private final WRITER writer;
033  @NonNull
034  private final DATATYPE_MANAGER datatypeManager;
035  @NonNull
036  private final IInlineStrategy inlineStrategy;
037
038  @NonNull
039  private final ModuleIndex moduleIndex;
040
041  public AbstractGenerationState(
042      @NonNull IModule module,
043      @NonNull WRITER writer,
044      @NonNull IConfiguration<SchemaGenerationFeature<?>> configuration,
045      @NonNull DATATYPE_MANAGER datatypeManager) {
046    this.module = module;
047    this.writer = writer;
048    this.datatypeManager = datatypeManager;
049    this.inlineStrategy = IInlineStrategy.newInlineStrategy(configuration);
050    this.moduleIndex = ModuleIndex.indexDefinitions(module, this.inlineStrategy);
051  }
052
053  @Override
054  public IModule getModule() {
055    return module;
056  }
057
058  @Override
059  public WRITER getWriter() {
060    return writer;
061  }
062
063  @NonNull
064  protected DATATYPE_MANAGER getDatatypeManager() {
065    return datatypeManager;
066  }
067
068  @NonNull
069  public ModuleIndex getMetaschemaIndex() {
070    return moduleIndex;
071  }
072
073  @Override
074  public boolean isInline(@NonNull IDefinition definition) {
075    return inlineStrategy.isInline(definition, getMetaschemaIndex());
076  }
077
078  /**
079   * Retrieve any allowed values that are context independent, meaning they always
080   * apply regardless of the location of the node in the larger graph.
081   *
082   * @param definition
083   *          the definition to get allowed values for
084   * @return the list of allowed values or an empty list
085   */
086  @NonNull
087  protected static AllowedValueCollection getContextIndependentEnumeratedValues(
088      @NonNull IValuedDefinition definition) {
089    List<IAllowedValue> values = new LinkedList<>();
090    boolean closed = false;
091    for (IAllowedValuesConstraint constraint : definition.getAllowedValuesConstraints()) {
092      assert constraint != null;
093      if (!constraint.isAllowedOther()) {
094        closed = true;
095      }
096
097      if (!IMetapathExpression.contextNode().getPath().equals(constraint.getTarget().getPath())) {
098        values = CollectionUtil.emptyList();
099        break;
100      }
101
102      values.addAll(constraint.getAllowedValues().values());
103    }
104    return new AllowedValueCollection(closed, values);
105  }
106
107  /**
108   * Get the name of the definition (and any parent instances/definition) to
109   * ensure an inline type is unique.
110   *
111   * @param definition
112   *          the definition to generate a type name for
113   * @param childModule
114   *          the module of the left node
115   * @return the unique type name
116   */
117  private CharSequence getTypeContext(
118      @NonNull IDefinition definition,
119      @NonNull IModule childModule) {
120    StringBuilder builder = new StringBuilder();
121    if (definition.isInline()) {
122      INamedInstance inlineInstance = definition.getInlineInstance();
123      IDefinition parentDefinition = inlineInstance.getContainingDefinition();
124
125      builder
126          .append(getTypeContext(parentDefinition, childModule))
127          .append(IGenerationState.toCamelCase(inlineInstance.getEffectiveName()));
128    } else {
129      builder.append(IGenerationState.toCamelCase(definition.getName()));
130    }
131    return builder;
132  }
133
134  @Override
135  @NonNull
136  public String getTypeNameForDefinition(@NonNull IDefinition definition, @Nullable String suffix) {
137    StringBuilder builder = new StringBuilder()
138        .append(IGenerationState.toCamelCase(definition.getModelType().name()))
139        .append(IGenerationState.toCamelCase(definition.getContainingModule().getShortName()));
140
141    if (isInline(definition)) {
142      builder.append(IGenerationState.toCamelCase(definition.getEffectiveName()));
143    } else {
144      // need to append the parent name(s) to disambiguate this type name
145      builder.append(getTypeContext(definition, definition.getContainingModule()));
146    }
147    if (suffix != null && !suffix.isBlank()) {
148      builder.append(suffix);
149    }
150    builder.append("Type");
151
152    return ObjectUtils.notNull(builder.toString());
153  }
154
155  public static class AllowedValueCollection {
156    private final boolean closed;
157    @NonNull
158    private final List<IAllowedValue> values;
159
160    public AllowedValueCollection(boolean closed, @NonNull List<IAllowedValue> values) {
161      this.closed = closed;
162      this.values = CollectionUtil.unmodifiableList(new ArrayList<>(values));
163    }
164
165    public boolean isClosed() {
166      return closed;
167    }
168
169    @NonNull
170    public List<IAllowedValue> getValues() {
171      return values;
172    }
173  }
174}