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