001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.oscal.lib.model.metadata; 007 008import gov.nist.secauto.metaschema.core.util.CollectionUtil; 009import gov.nist.secauto.oscal.lib.model.Property; 010 011import java.net.URI; 012import java.util.LinkedList; 013import java.util.List; 014import java.util.Objects; 015import java.util.Optional; 016import java.util.UUID; 017import java.util.stream.Collectors; 018import java.util.stream.Stream; 019 020import javax.xml.namespace.QName; 021 022import edu.umd.cs.findbugs.annotations.NonNull; 023 024public abstract class AbstractProperty implements IProperty { 025 026 @NonNull 027 public static QName qname(URI namespace, @NonNull String name) { 028 return new QName(normalizeNamespace(namespace).toString(), name); 029 } 030 031 @NonNull 032 public static QName qname(@NonNull String name) { 033 return new QName(OSCAL_NAMESPACE.toString(), name); 034 } 035 036 @NonNull 037 public static URI normalizeNamespace(URI namespace) { 038 URI propertyNamespace = namespace; 039 if (propertyNamespace == null) { 040 propertyNamespace = OSCAL_NAMESPACE; 041 } 042 return propertyNamespace; 043 } 044 045 @SuppressWarnings("null") 046 @NonNull 047 public static Optional<Property> find(List<Property> props, @NonNull QName qname) { 048 return CollectionUtil.listOrEmpty(props).stream().filter(prop -> qname.equals(prop.getQName())).findFirst(); 049 } 050 051 protected AbstractProperty() { 052 // only concrete classes should construct 053 } 054 055 public static List<Property> merge(@NonNull List<Property> original, @NonNull List<Property> additional) { 056 return Stream.concat(original.stream(), additional.stream()) 057 .collect(Collectors.toCollection(LinkedList::new)); 058 } 059 060 @Override 061 public boolean isNamespaceEqual(@NonNull URI namespace) { 062 return normalizeNamespace(getNs()).equals(namespace); 063 } 064 065 @NonNull 066 public QName getQName() { 067 return new QName(normalizeNamespace(getNs()).toString(), getName()); 068 } 069 070 @NonNull 071 public static Builder builder(@NonNull String name) { 072 return new Builder(name); 073 } 074 075 public static class Builder { 076 @NonNull 077 private final String name; 078 079 private UUID uuid; 080 private URI namespace; 081 private String value; 082 private String clazz; 083 084 public Builder(@NonNull String name) { 085 this.name = Objects.requireNonNull(name, "name"); 086 } 087 088 @NonNull 089 public Builder uuid(@NonNull UUID uuid) { 090 this.uuid = Objects.requireNonNull(uuid); 091 return this; 092 } 093 094 @SuppressWarnings("PMD.NullAssignment") // needed 095 @NonNull 096 public Builder namespace(@NonNull URI namespace) { 097 if (OSCAL_NAMESPACE.equals(namespace)) { 098 this.namespace = null; 099 } else { 100 this.namespace = Objects.requireNonNull(namespace); 101 } 102 return this; 103 } 104 105 @NonNull 106 public Builder value(@NonNull String value) { 107 this.value = Objects.requireNonNull(value); 108 return this; 109 } 110 111 @NonNull 112 public Builder clazz(@NonNull String clazz) { 113 this.clazz = Objects.requireNonNull(clazz); 114 return this; 115 } 116 117 @NonNull 118 public Property build() { 119 Property retval = new Property(); 120 retval.setName(name); 121 retval.setValue(Objects.requireNonNull(value, "value")); 122 if (uuid != null) { 123 retval.setUuid(uuid); 124 } 125 if (namespace != null) { 126 retval.setNs(namespace); 127 } 128 if (clazz != null) { 129 retval.setClazz(clazz); 130 } 131 132 return retval; 133 } 134 } 135}