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