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 }