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