001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.oscal.lib.model.control.catalog;
007
008import java.util.LinkedList;
009import java.util.List;
010import java.util.Objects;
011import java.util.stream.Stream;
012
013import dev.metaschema.core.datatype.markup.MarkupLine;
014import dev.metaschema.core.util.CollectionUtil;
015import dev.metaschema.core.util.ObjectUtils;
016import dev.metaschema.oscal.lib.model.CatalogGroup;
017import dev.metaschema.oscal.lib.model.Control;
018import dev.metaschema.oscal.lib.model.ControlPart;
019import dev.metaschema.oscal.lib.model.Link;
020import dev.metaschema.oscal.lib.model.Parameter;
021import dev.metaschema.oscal.lib.model.Property;
022import dev.metaschema.oscal.lib.model.control.AbstractParameter;
023import edu.umd.cs.findbugs.annotations.NonNull;
024
025public abstract class AbstractCatalogGroup
026    implements ICatalogGroup {
027
028  @NonNull
029  @Override
030  public Stream<String> getReferencedParameterIds() {
031
032    // get parameters referenced by the group's parts
033    Stream<String> insertIds = CollectionUtil.listOrEmpty(getParts()).stream()
034        // Get the full part hierarchy
035        .flatMap(part -> Stream.concat(Stream.of(part), part.getPartsRecursively()))
036        // Get the inserts for each part
037        .flatMap(part -> part.getInserts(insert -> "param".equals(insert.getType().toString())))
038        // Get the param ids for each insert
039        .map(insert -> insert.getIdReference().toString())
040        .flatMap(ObjectUtils::filterNull);
041
042    // get parameters referenced by the control's parameters
043    Stream<String> parameterIds = CollectionUtil.listOrEmpty(getParams()).stream()
044        .flatMap(ObjectUtils::filterNull)
045        .flatMap(AbstractParameter::getParameterReferences);
046
047    return ObjectUtils.notNull(
048        Stream.concat(insertIds, parameterIds).distinct());
049  }
050
051  @NonNull
052  public static Builder builder(@NonNull String id) {
053    return new Builder(id);
054  }
055
056  public static class Builder {
057    @NonNull
058    private final String id;
059
060    private String clazz;
061    private MarkupLine title;
062    private final List<Parameter> params = new LinkedList<>();
063    private final List<Property> props = new LinkedList<>();
064    private final List<Link> links = new LinkedList<>();
065    private final List<ControlPart> parts = new LinkedList<>();
066    private final List<CatalogGroup> groups = new LinkedList<>();
067    private final List<Control> controls = new LinkedList<>();
068
069    public Builder(@NonNull String id) {
070      this.id = ObjectUtils.requireNonNull(id, "id");
071    }
072
073    @NonNull
074    public Builder clazz(@NonNull String value) {
075      this.clazz = ObjectUtils.requireNonNull(value, "value");
076      return this;
077    }
078
079    @NonNull
080    public Builder title(@NonNull String markdown) {
081      this.title = MarkupLine.fromMarkdown(Objects.requireNonNull(markdown, "markdown"));
082      return this;
083    }
084
085    @NonNull
086    public Builder title(@NonNull MarkupLine value) {
087      this.title = ObjectUtils.requireNonNull(value, "value");
088      return this;
089    }
090
091    @NonNull
092    public Builder param(@NonNull Parameter value) {
093      this.params.add(Objects.requireNonNull(value, "value"));
094      return this;
095    }
096
097    @NonNull
098    public Builder prop(@NonNull Property value) {
099      this.props.add(Objects.requireNonNull(value, "value"));
100      return this;
101    }
102
103    @NonNull
104    public Builder link(@NonNull Link value) {
105      this.links.add(Objects.requireNonNull(value, "value"));
106      return this;
107    }
108
109    @NonNull
110    public Builder part(@NonNull ControlPart value) {
111      this.parts.add(Objects.requireNonNull(value, "value"));
112      return this;
113    }
114
115    @NonNull
116    public Builder group(@NonNull CatalogGroup value) {
117      this.groups.add(Objects.requireNonNull(value, "value"));
118      return this;
119    }
120
121    @NonNull
122    public Builder control(@NonNull Control value) {
123      this.controls.add(Objects.requireNonNull(value, "value"));
124      return this;
125    }
126
127    @NonNull
128    public CatalogGroup build() {
129      CatalogGroup retval = new CatalogGroup();
130      retval.setId(id);
131
132      if (title == null) {
133        throw new IllegalStateException("a title must be provided");
134      }
135      retval.setTitle(title);
136
137      if (clazz != null) {
138        retval.setClazz(clazz);
139      }
140      if (!params.isEmpty()) {
141        retval.setParams(params);
142      }
143      if (!props.isEmpty()) {
144        retval.setProps(props);
145      }
146      if (!links.isEmpty()) {
147        retval.setLinks(links);
148      }
149      if (!parts.isEmpty()) {
150        retval.setParts(parts);
151      }
152      if (!controls.isEmpty()) {
153        retval.setControls(controls);
154      }
155      if (!groups.isEmpty()) {
156        retval.setGroups(groups);
157      }
158
159      return retval;
160    }
161  }
162}