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}