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