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}