1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.oscal.lib.model.control;
7   
8   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
9   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
10  import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension;
11  import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
12  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
13  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
14  import gov.nist.secauto.oscal.lib.model.ControlPart;
15  import gov.nist.secauto.oscal.lib.model.Link;
16  import gov.nist.secauto.oscal.lib.model.Property;
17  
18  import java.net.URI;
19  import java.util.LinkedList;
20  import java.util.List;
21  import java.util.Objects;
22  import java.util.function.Predicate;
23  import java.util.stream.Stream;
24  
25  import edu.umd.cs.findbugs.annotations.NonNull;
26  
27  public abstract class AbstractPart implements IPart {
28  
29    @Override
30    @NonNull
31    public Stream<InsertAnchorExtension.InsertAnchorNode> getInserts(@NonNull Predicate<InsertAnchorNode> filter) {
32      MarkupMultiline prose = getProse();
33  
34      @NonNull
35      Stream<InsertAnchorExtension.InsertAnchorNode> retval;
36      if (prose == null) {
37        retval = ObjectUtils.notNull(Stream.empty());
38      } else {
39        List<InsertAnchorExtension.InsertAnchorNode> result = prose.getInserts(filter);
40        retval = ObjectUtils.notNull(result.stream());
41      }
42      return retval;
43    }
44  
45    public Stream<IPart> getPartsRecursively() {
46      return Stream.concat(
47          Stream.of(this),
48          CollectionUtil.listOrEmpty(getParts()).stream()
49              .flatMap(AbstractPart::getPartsRecursively));
50    }
51  
52    @NonNull
53    public static Builder builder(@NonNull String name) {
54      return new Builder(name);
55    }
56  
57    public static class Builder {
58      private String id;
59      @NonNull
60      private final String name;
61      private URI namespace;
62      private String clazz;
63      private MarkupMultiline prose;
64      private MarkupLine title;
65      private final List<Property> props = new LinkedList<>();
66      private final List<Link> links = new LinkedList<>();
67      private final List<ControlPart> parts = new LinkedList<>();
68  
69      public Builder(@NonNull String name) {
70        this.name = Objects.requireNonNull(name);
71      }
72  
73      @SuppressWarnings("PMD.ShortMethodName")
74      @NonNull
75      public Builder id(@NonNull String value) {
76        this.id = Objects.requireNonNull(value);
77        return this;
78      }
79  
80      @NonNull
81      public Builder namespace(@NonNull URI value) {
82        this.namespace = Objects.requireNonNull(value);
83        return this;
84      }
85  
86      @NonNull
87      public Builder clazz(@NonNull String value) {
88        this.clazz = Objects.requireNonNull(value);
89        return this;
90      }
91  
92      @NonNull
93      public Builder title(@NonNull String markdown) {
94        return title(MarkupLine.fromMarkdown(Objects.requireNonNull(markdown)));
95      }
96  
97      @NonNull
98      public Builder title(@NonNull MarkupLine value) {
99        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 }