001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.oscal.lib.model.control;
007
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.Collection;
011import java.util.LinkedList;
012import java.util.List;
013import java.util.Objects;
014import java.util.stream.Stream;
015
016import dev.metaschema.core.datatype.markup.MarkupLine;
017import dev.metaschema.core.datatype.markup.MarkupMultiline;
018import dev.metaschema.core.util.CollectionUtil;
019import dev.metaschema.core.util.ObjectUtils;
020import dev.metaschema.oscal.lib.model.Link;
021import dev.metaschema.oscal.lib.model.Parameter;
022import dev.metaschema.oscal.lib.model.ParameterConstraint;
023import dev.metaschema.oscal.lib.model.ParameterGuideline;
024import dev.metaschema.oscal.lib.model.ParameterSelection;
025import dev.metaschema.oscal.lib.model.Property;
026import dev.metaschema.oscal.lib.model.metadata.IProperty;
027import edu.umd.cs.findbugs.annotations.NonNull;
028
029public abstract class AbstractParameter implements IParameter {
030
031  @Override
032  public Stream<String> getParameterReferences() {
033
034    // handle prop name="aggregates"
035    Stream<String> aggregatesIds = CollectionUtil.listOrEmpty(getProps()).stream()
036        .filter(Objects::nonNull)
037        .filter(prop -> prop.isNamespaceEqual(IProperty.OSCAL_NAMESPACE) && "aggregates".equals(prop.getName()))
038        .map(Property::getValue);
039
040    // handle select/choice/insert
041    ParameterSelection selection = getSelect();
042
043    Stream<String> selectInsertIds;
044    if (selection == null) {
045      selectInsertIds = Stream.empty();
046    } else {
047      selectInsertIds = CollectionUtil.listOrEmpty(selection.getChoice()).stream()
048          .filter(Objects::nonNull)
049          .flatMap(choice -> choice.getInserts(insert -> "param".equals(insert.getType().toString())).stream()
050              .map(insert -> insert.getIdReference().toString()));
051    }
052    Stream<String> retval = Stream.concat(aggregatesIds, selectInsertIds)
053        .filter(Objects::nonNull)
054        .distinct();
055    assert retval != null;
056    return retval;
057  }
058
059  @NonNull
060  public static Builder builder(@NonNull String id) {
061    return new Builder(id);
062  }
063
064  public static class Builder {
065    @NonNull
066    private final String id;
067
068    private String clazz;
069    private final List<Property> props = new LinkedList<>();
070    private final List<Link> links = new LinkedList<>();
071    private MarkupLine label;
072    private MarkupMultiline usage;
073    private final List<ParameterConstraint> constraints = new LinkedList<>();
074    private final List<ParameterGuideline> guidelines = new LinkedList<>();
075    private List<String> values = new LinkedList<>();
076    private ParameterSelection selection;
077    private MarkupMultiline remarks;
078
079    public Builder(@NonNull String id) {
080      this.id = ObjectUtils.requireNonNull(id);
081    }
082
083    @NonNull
084    public Builder clazz(@NonNull String value) {
085      this.clazz = ObjectUtils.requireNonNull(value);
086      return this;
087    }
088
089    @NonNull
090    public Builder prop(@NonNull Property value) {
091      this.props.add(ObjectUtils.requireNonNull(value));
092      return this;
093    }
094
095    @NonNull
096    public Builder link(@NonNull Link value) {
097      this.links.add(ObjectUtils.requireNonNull(value));
098      return this;
099    }
100
101    @NonNull
102    public Builder label(@NonNull String markdown) {
103      return label(MarkupLine.fromMarkdown(Objects.requireNonNull(markdown)));
104    }
105
106    @NonNull
107    public Builder label(@NonNull MarkupLine value) {
108      this.label = ObjectUtils.requireNonNull(value);
109      return this;
110    }
111
112    @NonNull
113    public Builder usage(@NonNull String markdown) {
114      return usage(MarkupMultiline.fromMarkdown(ObjectUtils.requireNonNull(markdown)));
115    }
116
117    @NonNull
118    public Builder usage(@NonNull MarkupMultiline value) {
119      this.usage = ObjectUtils.requireNonNull(value);
120      return this;
121    }
122
123    @NonNull
124    public Builder constraint(@NonNull ParameterConstraint value) {
125      this.constraints.add(ObjectUtils.requireNonNull(value));
126      return this;
127    }
128
129    @NonNull
130    public Builder guideline(@NonNull ParameterGuideline value) {
131      this.guidelines.add(ObjectUtils.requireNonNull(value));
132      return this;
133    }
134
135    @SuppressWarnings("null")
136    @NonNull
137    public Builder values(@NonNull String... values) {
138      return values(Arrays.asList(values));
139    }
140
141    @NonNull
142    public Builder values(@NonNull Collection<String> values) {
143      this.values = new ArrayList<>(values);
144      return this;
145    }
146
147    @NonNull
148    public Builder select(@NonNull ParameterSelection value) {
149      this.selection = Objects.requireNonNull(value);
150      return this;
151    }
152
153    @NonNull
154    public Builder remarks(@NonNull MarkupMultiline value) {
155      this.remarks = Objects.requireNonNull(value);
156      return this;
157    }
158
159    @NonNull
160    public Parameter build() {
161      Parameter retval = new Parameter();
162      retval.setId(id);
163
164      if (clazz != null) {
165        retval.setClazz(clazz);
166      }
167      if (!props.isEmpty()) {
168        retval.setProps(props);
169      }
170      if (!links.isEmpty()) {
171        retval.setLinks(links);
172      }
173      if (label != null) {
174        retval.setLabel(label);
175      }
176      if (usage != null) {
177        retval.setUsage(usage);
178      }
179      if (!constraints.isEmpty()) {
180        retval.setConstraints(constraints);
181      }
182      if (!guidelines.isEmpty()) {
183        retval.setGuidelines(guidelines);
184      }
185      if (!values.isEmpty()) {
186        retval.setValues(values);
187      }
188      if (selection != null) {
189        retval.setSelect(selection);
190      }
191      if (remarks != null) {
192        retval.setRemarks(remarks);
193      }
194      return retval;
195    }
196  }
197}