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 <dfn>qualifiers</dfn>.
025 *
026 * <p>This class is currently not used by other classes in this package. It may be useful in a variety of dependency
027 * injection systems.</p>
028 *
029 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
030 *
031 * @see Attributes
032 */
033public class Qualifiers {
034
035
036  /*
037   * Static fields.
038   */
039
040
041  private static final Attributes QUALIFIER = Attributes.of("Qualifier");
042
043  private static final List<Attributes> QUALIFIERS = List.of(QUALIFIER);
044
045
046  /*
047   * Constructors.
048   */
049
050
051  /**
052   * Creates a new {@link Qualifiers}.
053   */
054  public Qualifiers() {
055    super();
056  }
057
058
059  /*
060   * Instance methods.
061   */
062
063
064  /**
065   * Returns an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link
066   * Attributes}.
067   *
068   * <p>The returned {@link Attributes} may be the supplied {@link Attributes} or a different instance.</p>
069   *
070   * @param a an {@link Attributes}; must not be {@code null}
071   *
072   * @return an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link
073   * Attributes}; never {@code null}
074   *
075   * @exception NullPointerException if {@code a} is {@code null}
076   */
077  public Attributes normalize(final Attributes a) {
078    return switch (a) {
079    case null -> throw new NullPointerException("a");
080    case Attributes q when this.qualifier().equals(q) -> this.qualifier();
081    default -> a;
082    };
083  }
084
085  /**
086   * Returns an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the
087   * supplied {@link List}.
088   *
089   * <p>The returned {@link List} may be the supplied {@link List} or a different instance.</p>
090   *
091   * @param list a {@link List} of {@link Attributes}s; must not be {@code null}
092   *
093   * @return an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the
094   * supplied {@link List}; never {@code null}
095   *
096   * @exception NullPointerException if {@code list} is {@code null}
097   */
098  public List<Attributes> normalize(final List<Attributes> list) {
099    return switch (list.size()) {
100    case 0 -> List.of();
101    case 1 -> list.equals(this.qualifiers()) ? this.qualifiers() : List.copyOf(list);
102    default -> {
103      final List<Attributes> l = new ArrayList<>(list.size());
104      for (final Attributes a : list) {
105        l.add(this.normalize(a));
106      }
107      yield Collections.unmodifiableList(l);
108    }
109    };
110  }
111
112  /**
113   * Returns the <dfn>qualifier</dfn> (meta-) qualifier.
114   *
115   * @return the <dfn>qualifier</dfn> (meta-) qualifier; never {@code null}
116   */
117  public Attributes qualifier() {
118    return QUALIFIER;
119  }
120
121  /**
122   * Returns {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to
123   * designate other {@link Attributes} as qualifiers.
124   *
125   * @param q an {@link Attributes}; must not be {@code null}
126   *
127   * @return {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to
128   * designate other {@link Attributes} as qualifiers
129   *
130   * @exception NullPointerException if {@code q} is {@code null}
131   */
132  public boolean qualifier(final Attributes q) {
133    return q.attributes().contains(this.qualifier());
134  }
135
136  /**
137   * Returns an immutable {@link List} consisting solely of the <dfn>qualifier</dfn> (meta-) qualifier.
138   *
139   * @return an immutable {@link List}; never {@code null}
140   *
141   * @see #qualifier()
142   */
143  public List<Attributes> qualifiers() {
144    return QUALIFIERS;
145  }
146
147  /**
148   * Returns an unmodifiable {@link List} consisting only of those {@link Attributes} in the supplied {@link
149   * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}.
150   *
151   * @param c a {@link Collection} of {@link Attributes}s; must not be {@code null}
152   *
153   * @return an unmodifiable {@link List} consisting only of those {@link Attributes}s in the supplied {@link
154   * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}; never {@code null}
155   *
156   * @exception NullPointerException if {@code c} is {@code null}
157   */
158  public List<Attributes> qualifiers(final Collection<? extends Attributes> c) {
159    return switch (c) {
160    case Collection<?> c0 when c0.isEmpty() -> List.of();
161    default -> {
162      final ArrayList<Attributes> list = new ArrayList<>(c.size());
163      for (final Attributes a : c) {
164        if (this.qualifier(a)) {
165          list.add(this.normalize(a));
166        }
167      }
168      list.trimToSize();
169      yield Collections.unmodifiableList(list);
170    }
171    };
172  }
173
174}