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