1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.model;
7   
8   import gov.nist.secauto.metaschema.core.util.CollectionUtil;
9   
10  import java.util.Map;
11  import java.util.Objects;
12  import java.util.Set;
13  
14  import edu.umd.cs.findbugs.annotations.NonNull;
15  
16  /**
17   * A marker interface for implementations that support a mapping of a namespaced
18   * key to a set of values.
19   */
20  public interface IAttributable {
21    @NonNull
22    String DEFAULT_PROPERY_NAMESPACE = IModule.XML_NAMESPACE;
23  
24    @NonNull
25    Map<Key, Set<String>> EMPTY = CollectionUtil.emptyMap();
26  
27    /**
28     * Get the mapping of property key to values.
29     *
30     * @return the mapping
31     */
32    @NonNull
33    default Map<Key, Set<String>> getProperties() {
34      return EMPTY;
35    }
36  
37    /**
38     * Determine if a property is defined.
39     *
40     * @param key
41     *          the key of the property
42     * @return {@code true} if the property is defined or {@code false} otherwise
43     */
44    default boolean hasProperty(@NonNull Key key) {
45      return getProperties().containsKey(key);
46    }
47  
48    /**
49     * Get the values associated with a given property key.
50     *
51     * @param key
52     *          the key of the property
53     * @return the values or an empty set
54     */
55    @NonNull
56    default Set<String> getPropertyValues(@NonNull Key key) {
57      Set<String> retval = getProperties().get(key);
58      if (retval == null) {
59        retval = CollectionUtil.emptySet();
60      }
61      return retval;
62    }
63  
64    /**
65     * Determine if a given property, with a given {@code key}, has the identified
66     * {@code value}.
67     *
68     * @param key
69     *          the key of the property
70     * @param value
71     *          the expected property value
72     * @return {@code true} if the property value is defined or {@code false}
73     *         otherwise
74     */
75    default boolean hasPropertyValue(@NonNull Key key, @NonNull String value) {
76      Set<String> values = getProperties().get(key);
77      return values != null && values.contains(value);
78    }
79  
80    /**
81     * Get a property key based on the provided name and namespace.
82     *
83     * @param name
84     *          the name portion of a property key
85     * @param namespace
86     *          the namespace portion of a property key
87     * @return the property key
88     */
89    @NonNull
90    static Key key(@NonNull String name, @NonNull String namespace) {
91      return new Key(name, namespace);
92    }
93  
94    /**
95     * Get a property key based on the provided name and the default namespace.
96     *
97     * @param name
98     *          the name portion of a property key
99     * @return the property key
100    * @see #DEFAULT_PROPERY_NAMESPACE
101    */
102   @NonNull
103   static Key key(@NonNull String name) {
104     return new Key(name);
105   }
106 
107   /**
108    * Represents a property key based on a name and a namespace.
109    */
110   @SuppressWarnings("PMD.ShortClassName")
111   final class Key {
112     @NonNull
113     private final String name;
114     @NonNull
115     private final String namespace;
116 
117     private Key(@NonNull String name) {
118       this(name, DEFAULT_PROPERY_NAMESPACE);
119     }
120 
121     private Key(@NonNull String name, @NonNull String namespace) {
122       this.name = name;
123       this.namespace = namespace;
124     }
125 
126     /**
127      * Get the property key's name portion.
128      *
129      * @return the name
130      */
131     @NonNull
132     public String getName() {
133       return name;
134     }
135 
136     /**
137      * Get the property key's namespace portion.
138      *
139      * @return the name
140      */
141     @NonNull
142     public String getNamespace() {
143       return namespace;
144     }
145 
146     @Override
147     public int hashCode() {
148       return Objects.hash(name, namespace);
149     }
150 
151     @SuppressWarnings("PMD.OnlyOneReturn")
152     @Override
153     public boolean equals(Object obj) {
154       if (this == obj) {
155         return true;
156       }
157       if (!(obj instanceof Key)) {
158         return false;
159       }
160       Key other = (Key) obj;
161       return Objects.equals(name, other.name) && Objects.equals(namespace, other.namespace);
162     }
163   }
164 }