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