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