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