1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.oscal.lib.model.metadata;
7   
8   import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
9   import gov.nist.secauto.metaschema.core.util.CollectionUtil;
10  import gov.nist.secauto.oscal.lib.model.Property;
11  
12  import java.net.URI;
13  import java.util.LinkedList;
14  import java.util.List;
15  import java.util.Objects;
16  import java.util.Optional;
17  import java.util.UUID;
18  import java.util.stream.Collectors;
19  import java.util.stream.Stream;
20  
21  import edu.umd.cs.findbugs.annotations.NonNull;
22  
23  public abstract class AbstractProperty implements IProperty {
24  
25    @NonNull
26    public static IEnhancedQName qname(URI namespace, @NonNull String name) {
27      return IEnhancedQName.of(normalizeNamespace(namespace).toASCIIString(), name);
28    }
29  
30    @NonNull
31    public static IEnhancedQName qname(@NonNull String name) {
32      return IEnhancedQName.of(OSCAL_NAMESPACE.toString(), name);
33    }
34  
35    @NonNull
36    public static URI normalizeNamespace(URI namespace) {
37      URI retval = namespace;
38      if (retval == null) {
39        retval = OSCAL_NAMESPACE;
40      }
41      return retval;
42    }
43  
44    @SuppressWarnings("null")
45    @NonNull
46    public static Optional<Property> find(List<Property> props, @NonNull IEnhancedQName qname) {
47      return CollectionUtil.listOrEmpty(props).stream().filter(prop -> qname.equals(prop.getQName())).findFirst();
48    }
49  
50    protected AbstractProperty() {
51      // only concrete classes should construct
52    }
53  
54    public static List<Property> merge(@NonNull List<Property> original, @NonNull List<Property> additional) {
55      return Stream.concat(original.stream(), additional.stream())
56          .collect(Collectors.toCollection(LinkedList::new));
57    }
58  
59    @Override
60    public boolean isNamespaceEqual(@NonNull URI namespace) {
61      return normalizeNamespace(getNs()).equals(namespace);
62    }
63  
64    @NonNull
65    public IEnhancedQName getQName() {
66      return qname(getNs(), getName());
67    }
68  
69    @NonNull
70    public static Builder builder(@NonNull String name) {
71      return new Builder(name);
72    }
73  
74    public static class Builder {
75      @NonNull
76      private final String name;
77  
78      private UUID uuid;
79      private URI namespace;
80      private String value;
81      private String clazz;
82  
83      public Builder(@NonNull String name) {
84        this.name = Objects.requireNonNull(name, "name");
85      }
86  
87      @NonNull
88      public Builder uuid(@NonNull UUID uuid) {
89        this.uuid = Objects.requireNonNull(uuid);
90        return this;
91      }
92  
93      @SuppressWarnings("PMD.NullAssignment") // needed
94      @NonNull
95      public Builder namespace(@NonNull URI namespace) {
96        if (OSCAL_NAMESPACE.equals(namespace)) {
97          this.namespace = null;
98        } else {
99          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 }