1 /*
2 * Copyright (C) 2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
3 */
4 package de.powerstat.validation.containers;
5
6
7 import java.util.Collection;
8 import java.util.Iterator;
9 import java.util.NoSuchElementException;
10 import java.util.Objects;
11 import java.util.Set;
12 import java.util.SortedSet;
13 import java.util.concurrent.ConcurrentSkipListSet;
14 import java.util.regex.Pattern;
15
16
17 /**
18 * Group of a specific type.
19 *
20 * @param <T> Use only entities
21 */
22 public class GroupOf<T> implements Set<T>
23 {
24 /**
25 * Group name regexp.
26 */
27 private static final Pattern GROUPNAME_REGEXP = Pattern.compile("^[\\p{L}][\\p{L}-]*$"); //$NON-NLS-1$
28
29 /**
30 * Group name.
31 */
32 private final String name;
33
34 /**
35 * Group.
36 */
37 private final SortedSet<T> group = new ConcurrentSkipListSet<>();
38
39
40 /**
41 * Constructor.
42 *
43 * @param groupName Group name (maximum 40 characters)
44 */
45 public GroupOf(final String groupName)
46 {
47 super();
48 Objects.requireNonNull(groupName, "groupName"); //$NON-NLS-1$
49 if ((groupName.length() < 1) || (groupName.length() > 40))
50 {
51 throw new IllegalArgumentException("groupName with wrong length"); //$NON-NLS-1$
52 }
53 if (!GroupOf.GROUPNAME_REGEXP.matcher(groupName).matches())
54 {
55 throw new IllegalArgumentException("groupName with wrong format"); //$NON-NLS-1$
56 }
57 this.name = groupName;
58 }
59
60
61 /**
62 * Returns the name of this GroupOf.
63 *
64 * @return The name of this group.
65 */
66 public String name()
67 {
68 return this.name;
69 }
70
71
72 /**
73 * Calculate hash code.
74 *
75 * @return Hash
76 * @see java.lang.Object#hashCode()
77 */
78 @Override
79 public int hashCode()
80 {
81 return Objects.hash(this.name, this.group);
82 }
83
84
85 /**
86 * Is equal with another object.
87 *
88 * @param obj Object
89 * @return true when equal, false otherwise
90 * @throws NoSuchElementException If there is no entry in this GroupOf
91 * @see java.lang.Object#equals(java.lang.Object)
92 */
93 @Override
94 public boolean equals(final Object obj)
95 {
96 if (this == obj)
97 {
98 return true;
99 }
100 if (!(obj instanceof GroupOf<?>))
101 // if ((obj == null) || (this.getClass() != obj.getClass()))
102 {
103 return false;
104 }
105 final GroupOf<T> other = (GroupOf<T>)obj;
106 return this.name.equals(other.name) && this.group.equals(other.group);
107 }
108
109
110 /**
111 * Returns the string representation of this GroupOf.
112 *
113 * The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
114 *
115 * "GroupOf<>[, ...]"
116 *
117 * @return String representation of this GroupOf
118 * @see java.lang.Object#toString()
119 */
120 @Override
121 public String toString()
122 {
123 final var builder = new StringBuilder();
124 builder.append("GroupOf<>[name="); //$NON-NLS-1$
125 builder.append(this.name);
126 builder.append(", ");
127 final int initLength = builder.length();
128 for (final T entry : this.group)
129 {
130 builder.append(entry);
131 builder.append(", "); //$NON-NLS-1$
132 }
133 if (", ".equals(builder.substring(builder.length() - 2)))
134 {
135 builder.setLength(builder.length() - 2);
136 }
137 builder.append(']');
138 return builder.toString();
139 }
140
141
142 /**
143 * Returns the number of elements in this set (its cardinality).
144 *
145 * @return The number of elements in this set (its cardinality)
146 */
147 @Override
148 public int size()
149 {
150 return this.group.size();
151 }
152
153
154 /**
155 * Returns true if this set contains no elements.
156 *
157 * @return True if this set contains no elements
158 */
159 @Override
160 public boolean isEmpty()
161 {
162 return this.group.isEmpty();
163 }
164
165
166 /**
167 * Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
168 *
169 * @param o Element whose presence in this set is to be tested
170 * @return true if this set contains the specified element
171 */
172 @Override
173 public boolean contains(final Object o)
174 {
175 return this.group.contains(o);
176 }
177
178
179 /**
180 * Returns an iterator over the elements in this set. The elements are returned in no particular order (unless this set is an instance of some class that provides a guarantee).
181 *
182 * @return An iterator over the elements in this set
183 */
184 @Override
185 public Iterator<T> iterator()
186 {
187 return this.group.iterator();
188 }
189
190
191 /**
192 * Returns an array containing all of the elements in this set. If this set makes any guarantees as to what order its elements are returned by its iterator, this method must return the elements in the same order.
193 *
194 * @return An array containing all the elements in this set
195 */
196 @Override
197 public Object[] toArray()
198 {
199 return this.group.toArray();
200 }
201
202
203 /**
204 * Returns an array containing all of the elements in this set; the runtime type of the returned array is that of the specified array. If the set fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this set.
205 *
206 * @param a The array into which the elements of this set are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
207 * @return An array containing all the elements in this set
208 */
209 @Override
210 public <T> T[] toArray(final T[] a)
211 {
212 return this.group.toArray(a);
213 }
214
215
216 /**
217 * Adds the specified element to this set if it is not already present.
218 *
219 * @param e Element to be added to this set
220 * @return true if this set did not already contain the specified element
221 */
222 @Override
223 public boolean add(final T e)
224 {
225 return this.group.add(e);
226 }
227
228
229 /**
230 * Removes the specified element from this set if it is present.
231 *
232 * @param o object to be removed from this set, if present
233 * @return true if this set contained the specified element
234 */
235 @Override
236 public boolean remove(final Object o)
237 {
238 return this.group.remove(o);
239 }
240
241
242 /**
243 * Returns true if this set contains all of the elements of the specified collection. If the specified collection is also a set, this method returns true if it is a subset of this set.
244 *
245 * @param c Collection to be checked for containment in this set
246 * @return true if this set contains all of the elements of the specified collection
247 */
248 @Override
249 public boolean containsAll(final Collection<?> c)
250 {
251 return this.group.containsAll(c);
252 }
253
254
255 /**
256 * Returns true if this set contains all of the elements of the specified collection. If the specified collection is also a set, this method returns true if it is a subset of this set.
257 *
258 * @param c Collection to be checked for containment in this set
259 * @return true if this set contains all of the elements of the specified collection
260 */
261 @Override
262 public boolean addAll(final Collection<? extends T> c)
263 {
264 return this.group.addAll(c);
265 }
266
267
268 /**
269 * Retains only the elements in this set that are contained in the specified collection.
270 *
271 * @param c Collection containing elements to be retained in this set
272 * @return true if this set changed as a result of the call
273 */
274 @Override
275 public boolean retainAll(final Collection<?> c)
276 {
277 return this.group.retainAll(c);
278 }
279
280
281 /**
282 * Removes from this set all of its elements that are contained in the specified collection.
283 *
284 * @param c Collection containing elements to be removed from this set
285 * @return true if this set changed as a result of the call
286 */
287 @Override
288 public boolean removeAll(final Collection<?> c)
289 {
290 return this.group.removeAll(c);
291 }
292
293
294 /**
295 * Removes all of the elements from this set (optional operation). The set will be empty after this call returns.
296 */
297 @Override
298 public void clear()
299 {
300 this.group.clear();
301 }
302
303 }