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