001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.assign; 015 016import java.util.ArrayList; 017import java.util.Collection; 018import java.util.Collections; 019import java.util.List; 020 021import org.microbean.attributes.Attributes; 022 023/** 024 * A utility class for working with commonly-used <dfn>qualifiers</dfn>. 025 * 026 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 027 * 028 * @see Attributes 029 */ 030public final class Qualifiers { 031 032 private static final Attributes QUALIFIER = Attributes.of("Qualifier"); 033 034 private static final List<Attributes> QUALIFIERS = List.of(QUALIFIER); 035 036 private static final Attributes ANY_QUALIFIER = Attributes.of("Any", QUALIFIERS); 037 038 private static final List<Attributes> ANY_QUALIFIERS = List.of(ANY_QUALIFIER); 039 040 private static final Attributes DEFAULT_QUALIFIER = Attributes.of("Default", QUALIFIERS); 041 042 private static final List<Attributes> DEFAULT_QUALIFIERS = List.of(DEFAULT_QUALIFIER); 043 044 private static final List<Attributes> ANY_AND_DEFAULT_QUALIFIERS = List.of(ANY_QUALIFIER, DEFAULT_QUALIFIER); 045 046 private static final Attributes PRIMORDIAL_QUALIFIER = Attributes.of("Primordial", QUALIFIERS); 047 048 private static final List<Attributes> PRIMORDIAL_QUALIFIERS = List.of(PRIMORDIAL_QUALIFIER); 049 050 private Qualifiers() { 051 super(); 052 } 053 054 /** 055 * Returns an unmodifiable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn> and the 056 * <dfn>default qualifier</dfn>. 057 * 058 * @return an unmodifiable {@link List} consisting solely of the unattributed any qualifier and the default qualifier; 059 * never {@code null} 060 * 061 * @see #anyQualifier() 062 * 063 * @see #defaultQualifier() 064 */ 065 public static final List<Attributes> anyAndDefaultQualifiers() { 066 return ANY_AND_DEFAULT_QUALIFIERS; 067 } 068 069 /** 070 * Returns the unattributed <dfn>any qualifier</dfn>. 071 * 072 * @return the <dfn>any qualifier</dfn>; never {@code null} 073 * 074 * @see #anyQualifiers() 075 */ 076 public static final Attributes anyQualifier() { 077 return ANY_QUALIFIER; 078 } 079 080 /** 081 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal 082 * to} the unattributed {@linkplain #anyQualifier() any qualifier}. 083 * 084 * @param a an {@link Attributes}; must not be {@code null} 085 * 086 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal 087 * to} the unattributed {@linkplain #anyQualifier() any qualifier} 088 * 089 * @exception NullPointerException if {@code a} is {@code null} 090 */ 091 public static final boolean anyQualifier(final Attributes a) { 092 return ANY_QUALIFIER == a || anyQualifier().equals(a) && qualifier(a); 093 } 094 095 /** 096 * Returns an immutable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn>. 097 * 098 * @return an immutable {@link List}; never {@code null} 099 * 100 * @see #anyQualifier() 101 */ 102 public static final List<Attributes> anyQualifiers() { 103 return ANY_QUALIFIERS; 104 } 105 106 /** 107 * Returns the <dfn>default qualifier</dfn>. 108 * 109 * @return the <dfn>default qualifier</dfn>; never {@code null} 110 * 111 * @see #defaultQualifiers() 112 */ 113 public static final Attributes defaultQualifier() { 114 return DEFAULT_QUALIFIER; 115 } 116 117 /** 118 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain 119 * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier}. 120 * 121 * @param a an {@link Attributes}; must not be {@code null} 122 * 123 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain 124 * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier} 125 * 126 * @exception NullPointerException if {@code a} is {@code null} 127 */ 128 public static final boolean defaultQualifier(final Attributes a) { 129 return DEFAULT_QUALIFIER == a || defaultQualifier().equals(a) && qualifier(a); 130 } 131 132 /** 133 * Returns an immutable {@link List} consisting solely of the <dfn>default qualifier</dfn>. 134 * 135 * @return an immutable {@link List}; never {@code null} 136 * 137 * @see #defaultQualifier() 138 */ 139 public static final List<Attributes> defaultQualifiers() { 140 return DEFAULT_QUALIFIERS; 141 } 142 143 /** 144 * Returns an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link 145 * Attributes}. 146 * 147 * <p>The returned {@link Attributes} may be the supplied {@link Attributes} or a different instance.</p> 148 * 149 * @param a an {@link Attributes}; must not be {@code null} 150 * 151 * @return an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link 152 * Attributes}; never {@code null} 153 * 154 * @exception NullPointerException if {@code a} is {@code null} 155 */ 156 public static final Attributes normalize(final Attributes a) { 157 return switch (a) { 158 case null -> throw new NullPointerException("a"); 159 case Attributes q when defaultQualifier(q) -> defaultQualifier(); 160 case Attributes q when QUALIFIER.equals(q) -> qualifier(); 161 default -> a; 162 }; 163 } 164 165 /** 166 * Returns an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the 167 * supplied {@link List}. 168 * 169 * <p>The returned {@link List} may be the supplied {@link List} or a different instance.</p> 170 * 171 * @param list a {@link List} of {@link Attributes}s; must not be {@code null} 172 * 173 * @return an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the 174 * supplied {@link List}; never {@code null} 175 * 176 * @exception NullPointerException if {@code list} is {@code null} 177 */ 178 public static final List<Attributes> normalize(final List<Attributes> list) { 179 return switch (list.size()) { 180 case 0 -> List.of(); 181 case 1 -> list.equals(defaultQualifiers()) ? defaultQualifiers() : List.copyOf(list); 182 default -> { 183 final List<Attributes> l = new ArrayList<>(list.size()); 184 for (final Attributes a : list) { 185 l.add(normalize(a)); 186 } 187 yield Collections.unmodifiableList(l); 188 } 189 }; 190 } 191 192 /** 193 * Returns the <dfn>primordial qualifier</dfn>. 194 * 195 * @return the <dfn>primordial qualifier</dfn>; never {@code null} 196 * 197 * @see #primordialQualifiers() 198 */ 199 public static final Attributes primordialQualifier() { 200 return PRIMORDIAL_QUALIFIER; 201 } 202 203 /** 204 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain 205 * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier}. 206 * 207 * @param a an {@link Attributes}; must not be {@code null} 208 * 209 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain 210 * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier} 211 * 212 * @exception NullPointerException if {@code a} is {@code null} 213 */ 214 public static final boolean primordialQualifier(final Attributes a) { 215 return PRIMORDIAL_QUALIFIER == a || primordialQualifier().equals(a) && qualifier(a); 216 } 217 218 /** 219 * Returns an immutable {@link List} consisting solely of the <dfn>primordial qualifier</dfn>. 220 * 221 * @return an immutable {@link List}; never {@code null} 222 * 223 * @see #primordialQualifier() 224 */ 225 public static final List<Attributes> primordialQualifiers() { 226 return PRIMORDIAL_QUALIFIERS; 227 } 228 229 /** 230 * Returns the <dfn>qualifier</dfn> (meta-) qualifier. 231 * 232 * @return the <dfn>qualifier</dfn> (meta-) qualifier; never {@code null} 233 */ 234 public static final Attributes qualifier() { 235 return QUALIFIER; 236 } 237 238 /** 239 * Returns {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to 240 * designate other {@link Attributes} as qualifiers. 241 * 242 * @param q an {@link Attributes}; must not be {@code null} 243 * 244 * @return {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to 245 * designate other {@link Attributes} as qualifiers 246 * 247 * @exception NullPointerException if {@code q} is {@code null} 248 */ 249 public static final boolean qualifier(final Attributes q) { 250 return q.attributes().contains(qualifier()); 251 } 252 253 /** 254 * Returns an immutable {@link List} consisting solely of the <dfn>qualifier</dfn> (meta-) qualifier. 255 * 256 * @return an immutable {@link List}; never {@code null} 257 * 258 * @see #qualifier() 259 */ 260 public static final List<Attributes> qualifiers() { 261 return QUALIFIERS; 262 } 263 264 /** 265 * Returns an unmodifiable {@link List} consisting only of those {@link Attributes} in the supplied {@link 266 * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}. 267 * 268 * @param c a {@link Collection} of {@link Attributes}s; must not be {@code null} 269 * 270 * @return an unmodifiable {@link List} consisting only of those {@link Attributes}s in the supplied {@link 271 * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}; never {@code null} 272 * 273 * @exception NullPointerException if {@code c} is {@code null} 274 */ 275 public static final List<Attributes> qualifiers(final Collection<? extends Attributes> c) { 276 return switch (c) { 277 case Collection<?> c0 when c0.isEmpty() -> List.of(); 278 case Collection<?> c0 when c0.equals(defaultQualifiers()) -> defaultQualifiers(); 279 case Collection<?> c0 when c0.equals(anyAndDefaultQualifiers()) -> anyAndDefaultQualifiers(); 280 default ->{ 281 final ArrayList<Attributes> list = new ArrayList<>(c.size()); 282 for (final Attributes a : c) { 283 if (qualifier(a)) { 284 list.add(normalize(a)); 285 } 286 } 287 list.trimToSize(); 288 yield Collections.unmodifiableList(list); 289 } 290 }; 291 } 292 293}