001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.oscal.lib.model.control;
007
008import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
009import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
010import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension;
011import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
012import gov.nist.secauto.metaschema.core.util.CollectionUtil;
013import gov.nist.secauto.metaschema.core.util.ObjectUtils;
014import gov.nist.secauto.oscal.lib.model.ControlPart;
015import gov.nist.secauto.oscal.lib.model.Link;
016import gov.nist.secauto.oscal.lib.model.Property;
017
018import java.net.URI;
019import java.util.LinkedList;
020import java.util.List;
021import java.util.Objects;
022import java.util.function.Predicate;
023import java.util.stream.Stream;
024
025import edu.umd.cs.findbugs.annotations.NonNull;
026
027public abstract class AbstractPart implements IPart {
028
029  @Override
030  @NonNull
031  public Stream<InsertAnchorExtension.InsertAnchorNode> getInserts(@NonNull Predicate<InsertAnchorNode> filter) {
032    MarkupMultiline prose = getProse();
033
034    @NonNull
035    Stream<InsertAnchorExtension.InsertAnchorNode> retval;
036    if (prose == null) {
037      retval = ObjectUtils.notNull(Stream.empty());
038    } else {
039      List<InsertAnchorExtension.InsertAnchorNode> result = prose.getInserts(filter);
040      retval = ObjectUtils.notNull(result.stream());
041    }
042    return retval;
043  }
044
045  public Stream<IPart> getPartsRecursively() {
046    return Stream.concat(
047        Stream.of(this),
048        CollectionUtil.listOrEmpty(getParts()).stream()
049            .flatMap(AbstractPart::getPartsRecursively));
050  }
051
052  @NonNull
053  public static Builder builder(@NonNull String name) {
054    return new Builder(name);
055  }
056
057  public static class Builder {
058    private String id;
059    @NonNull
060    private final String name;
061    private URI namespace;
062    private String clazz;
063    private MarkupMultiline prose;
064    private MarkupLine title;
065    private final List<Property> props = new LinkedList<>();
066    private final List<Link> links = new LinkedList<>();
067    private final List<ControlPart> parts = new LinkedList<>();
068
069    public Builder(@NonNull String name) {
070      this.name = Objects.requireNonNull(name);
071    }
072
073    @SuppressWarnings("PMD.ShortMethodName")
074    @NonNull
075    public Builder id(@NonNull String value) {
076      this.id = Objects.requireNonNull(value);
077      return this;
078    }
079
080    @NonNull
081    public Builder namespace(@NonNull URI value) {
082      this.namespace = Objects.requireNonNull(value);
083      return this;
084    }
085
086    @NonNull
087    public Builder clazz(@NonNull String value) {
088      this.clazz = Objects.requireNonNull(value);
089      return this;
090    }
091
092    @NonNull
093    public Builder title(@NonNull String markdown) {
094      return title(MarkupLine.fromMarkdown(Objects.requireNonNull(markdown)));
095    }
096
097    @NonNull
098    public Builder title(@NonNull MarkupLine value) {
099      this.title = Objects.requireNonNull(value);
100      return this;
101    }
102
103    @NonNull
104    public Builder prose(@NonNull String markdown) {
105      return prose(MarkupMultiline.fromMarkdown(Objects.requireNonNull(markdown)));
106    }
107
108    @NonNull
109    public Builder prose(@NonNull MarkupMultiline value) {
110      this.prose = Objects.requireNonNull(value);
111      return this;
112    }
113
114    @NonNull
115    public Builder prop(@NonNull Property value) {
116      this.props.add(Objects.requireNonNull(value));
117      return this;
118    }
119
120    @NonNull
121    public Builder link(@NonNull Link value) {
122      this.links.add(Objects.requireNonNull(value));
123      return this;
124    }
125
126    @NonNull
127    public Builder part(@NonNull ControlPart value) {
128      this.parts.add(Objects.requireNonNull(value));
129      return this;
130    }
131
132    @NonNull
133    public ControlPart build() {
134      ControlPart retval = new ControlPart();
135
136      retval.setName(name);
137
138      if (id != null) {
139        retval.setId(id);
140      }
141      if (namespace != null) {
142        retval.setNs(namespace);
143      }
144      if (clazz != null) {
145        retval.setClazz(clazz);
146      }
147      if (prose != null) {
148        retval.setProse(prose);
149      }
150      if (title != null) {
151        retval.setTitle(title);
152      }
153      if (!props.isEmpty()) {
154        retval.setProps(props);
155      }
156      if (!links.isEmpty()) {
157        retval.setLinks(links);
158      }
159      if (!parts.isEmpty()) {
160        retval.setParts(parts);
161      }
162      return retval;
163    }
164  }
165}