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   // FIXME: use IEnhancedQName instead of name and namespace, or replace key
110   // altogether with an integer value
111   @SuppressWarnings("PMD.ShortClassName")
112   final class Key {
113     @NonNull
114     private final String name;
115     @NonNull
116     private final String namespace;
117 
118     private Key(@NonNull String name) {
119       this(name, DEFAULT_PROPERY_NAMESPACE);
120     }
121 
122     private Key(@NonNull String name, @NonNull String namespace) {
123       this.name = name;
124       this.namespace = namespace;
125     }
126 
127     /**
128      * Get the property key's name portion.
129      *
130      * @return the name
131      */
132     @NonNull
133     public String getName() {
134       return name;
135     }
136 
137     /**
138      * Get the property key's namespace portion.
139      *
140      * @return the name
141      */
142     @NonNull
143     public String getNamespace() {
144       return namespace;
145     }
146 
147     @Override
148     public int hashCode() {
149       return Objects.hash(name, namespace);
150     }
151 
152     @SuppressWarnings("PMD.OnlyOneReturn")
153     @Override
154     public boolean equals(Object obj) {
155       if (this == obj) {
156         return true;
157       }
158       if (!(obj instanceof Key)) {
159         return false;
160       }
161       Key other = (Key) obj;
162       return Objects.equals(name, other.name) && Objects.equals(namespace, other.namespace);
163     }
164   }
165 }