001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.oscal.lib.model.control;
028
029import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupLine;
030import gov.nist.secauto.metaschema.model.common.datatype.markup.MarkupMultiline;
031import gov.nist.secauto.metaschema.model.common.util.CollectionUtil;
032import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
033import gov.nist.secauto.oscal.lib.model.Link;
034import gov.nist.secauto.oscal.lib.model.Parameter;
035import gov.nist.secauto.oscal.lib.model.ParameterConstraint;
036import gov.nist.secauto.oscal.lib.model.ParameterGuideline;
037import gov.nist.secauto.oscal.lib.model.ParameterSelection;
038import gov.nist.secauto.oscal.lib.model.Property;
039import gov.nist.secauto.oscal.lib.model.metadata.IProperty;
040
041import java.util.ArrayList;
042import java.util.Arrays;
043import java.util.Collection;
044import java.util.LinkedList;
045import java.util.List;
046import java.util.Objects;
047import java.util.stream.Stream;
048
049import edu.umd.cs.findbugs.annotations.NonNull;
050
051public abstract class AbstractParameter implements IParameter {
052
053  @Override
054  public Stream<String> getParameterReferences() {
055
056    // handle prop name="aggregates"
057    Stream<String> aggregatesIds = CollectionUtil.listOrEmpty(getProps()).stream()
058        .filter(Objects::nonNull)
059        .filter(prop -> prop.isNamespaceEqual(IProperty.OSCAL_NAMESPACE) && "aggregates".equals(prop.getName()))
060        .map(prop -> prop.getValue());
061
062    // handle select/choice/insert
063    ParameterSelection selection = getSelect();
064
065    Stream<String> selectInsertIds;
066    if (selection == null) {
067      selectInsertIds = Stream.empty();
068    } else {
069      selectInsertIds = CollectionUtil.listOrEmpty(selection.getChoice()).stream()
070          .filter(Objects::nonNull)
071          .flatMap(choice -> choice.getInserts(insert -> "param".equals(insert.getType().toString())).stream()
072              .map(insert -> insert.getIdReference().toString()));
073    }
074    Stream<String> retval = Stream.concat(aggregatesIds, selectInsertIds)
075        .filter(Objects::nonNull)
076        .distinct();
077    assert retval != null;
078    return retval;
079  }
080
081  @NonNull
082  public static Builder builder(@NonNull String id) {
083    return new Builder(id);
084  }
085
086  public static class Builder {
087    @NonNull
088    private final String id;
089
090    private String clazz;
091    private final List<Property> props = new LinkedList<>();
092    private final List<Link> links = new LinkedList<>();
093    private MarkupLine label;
094    private MarkupMultiline usage;
095    private final List<ParameterConstraint> constraints = new LinkedList<>();
096    private final List<ParameterGuideline> guidelines = new LinkedList<>();
097    private List<String> values = new LinkedList<>();
098    private ParameterSelection selection;
099    private MarkupMultiline remarks;
100
101    public Builder(@NonNull String id) {
102      this.id = ObjectUtils.requireNonNull(id);
103    }
104
105    @NonNull
106    public Builder clazz(@NonNull String value) {
107      this.clazz = ObjectUtils.requireNonNull(value);
108      return this;
109    }
110
111    @NonNull
112    public Builder prop(@NonNull Property value) {
113      this.props.add(ObjectUtils.requireNonNull(value));
114      return this;
115    }
116
117    @NonNull
118    public Builder link(@NonNull Link value) {
119      this.links.add(ObjectUtils.requireNonNull(value));
120      return this;
121    }
122
123    @NonNull
124    public Builder label(@NonNull String markdown) {
125      return label(MarkupLine.fromMarkdown(Objects.requireNonNull(markdown)));
126    }
127
128    @NonNull
129    public Builder label(@NonNull MarkupLine value) {
130      this.label = ObjectUtils.requireNonNull(value);
131      return this;
132    }
133
134    @NonNull
135    public Builder usage(@NonNull String markdown) {
136      return usage(MarkupMultiline.fromMarkdown(ObjectUtils.requireNonNull(markdown)));
137    }
138
139    @NonNull
140    public Builder usage(@NonNull MarkupMultiline value) {
141      this.usage = ObjectUtils.requireNonNull(value);
142      return this;
143    }
144
145    @NonNull
146    public Builder constraint(@NonNull ParameterConstraint value) {
147      this.constraints.add(ObjectUtils.requireNonNull(value));
148      return this;
149    }
150
151    @NonNull
152    public Builder guideline(@NonNull ParameterGuideline value) {
153      this.guidelines.add(ObjectUtils.requireNonNull(value));
154      return this;
155    }
156
157    @SuppressWarnings("null")
158    @NonNull
159    public Builder values(@NonNull String... values) {
160      return values(Arrays.asList(values));
161    }
162
163    @NonNull
164    public Builder values(@NonNull Collection<String> values) {
165      this.values = new ArrayList<>(values);
166      return this;
167    }
168
169    @NonNull
170    public Builder select(@NonNull ParameterSelection value) {
171      this.selection = Objects.requireNonNull(value);
172      return this;
173    }
174
175    @NonNull
176    public Builder remarks(@NonNull MarkupMultiline value) {
177      this.remarks = Objects.requireNonNull(value);
178      return this;
179    }
180
181    @NonNull
182    public Parameter build() {
183      Parameter retval = new Parameter();
184      retval.setId(id);
185
186      if (clazz != null) {
187        retval.setClazz(clazz);
188      }
189      if (!props.isEmpty()) {
190        retval.setProps(props);
191      }
192      if (!links.isEmpty()) {
193        retval.setLinks(links);
194      }
195      if (label != null) {
196        retval.setLabel(label);
197      }
198      if (usage != null) {
199        retval.setUsage(usage);
200      }
201      if (!constraints.isEmpty()) {
202        retval.setConstraints(constraints);
203      }
204      if (!guidelines.isEmpty()) {
205        retval.setGuidelines(guidelines);
206      }
207      if (!values.isEmpty()) {
208        retval.setValues(values);
209      }
210      if (selection != null) {
211        retval.setSelect(selection);
212      }
213      if (remarks != null) {
214        retval.setRemarks(remarks);
215      }
216      return retval;
217    }
218  }
219}