001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2018–2019 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.microprofile.config;
018
019import java.util.Comparator;
020
021import org.eclipse.microprofile.config.spi.ConfigSource;
022
023/**
024 * A {@link Comparator} of {@link ConfigSource}s that considers only
025 * their {@linkplain ConfigSource#getOrdinal() ordinals} and
026 * {@linkplain ConfigSource#getName() names} in accordance with the
027 * minimal requirements of the MicroProfile Config specification as
028 * spelled out (only) in the {@linkplain ConfigSource
029 * <code>ConfigSource</code> API documentation}.
030 *
031 * <p><strong>This {@link Comparator} implementation is, and must be,
032 * inconsistent with {@link Object#equals(Object) equals()}</strong>,
033 * as implied by the same specification.</p>
034 *
035 * <p>Note that the requirement to use a {@link ConfigSource}'s
036 * {@linkplain ConfigSource#getName() name} as a secondary sorting key
037 * is defined only in the {@linkplain ConfigSource#getOrdinal()
038 * javadocs of the <code>ConfigSource.getOrdinal()</code> method}.</p>
039 *
040 * <p>Note further that there are no guidelines or requirements about
041 * what format a {@link ConfigSource}'s {@linkplain
042 * ConfigSource#getName() name} must take, so in effect the ordering
043 * of two {@link ConfigSource}s that have a common {@linkplain
044 * ConfigSource#getOrdinal() ordinal} is undefined.</p>
045 *
046 * @author <a href="https://about.me/lairdnelson"
047 * target="_parent">Laird Nelson</a>
048 *
049 * @see #compare(ConfigSource, ConfigSource)
050 *
051 * @see ConfigSource
052 *
053 * @see ConfigSource#getOrdinal()
054 *
055 * @see ConfigSource#getName()
056 */
057public final class ConfigSourceComparator implements Comparator<ConfigSource> {
058
059
060  /*
061   * Static fields.
062   */
063
064  
065  /**
066   * The sole instance of this class.
067   */
068  public static final ConfigSourceComparator INSTANCE = new ConfigSourceComparator();
069
070
071  /*
072   * Constructors.
073   */  
074  
075
076  /**
077   * Creates a new {@link ConfigSourceComparator}.
078   */
079  private ConfigSourceComparator() {
080    super();
081  }
082
083
084  /*
085   * Instance methods.
086   */
087  
088
089  /**
090   * Compares two {@link ConfigSource}s, returning {@code -1} if the
091   * first has an {@linkplain ConfigSource#getOrdinal() ordinal}
092   * greater than that of the second and {@code 1} if the second has
093   * an {@linkplain ConfigSource#getOrdinal() ordinal} greater than
094   * that of the first, and then the result of invoking {@link
095   * String#compareTo(String)} on the return values of the {@link
096   * ConfigSource}s' respective {@link ConfigSource#getName()}
097   * methods.
098   *
099   * <p><strong>This method may return {@code 0} when both {@link
100   * ConfigSource}s are not otherwise semantically equal.</strong></p>
101   *
102   * @param firstConfigSource the first of two {@link ConfigSource}s;
103   * may be {@code null}
104   *
105   * @param secondConfigSource the second of two {@link
106   * ConfigSource}s; may be {@code null}
107   *
108   * @return {@code -1} if the first {@link ConfigSource} has an
109   * {@linkplain ConfigSource#getOrdinal() ordinal} greater than that
110   * of the second, {@code 1} if the second {@link ConfigSource} has
111   * an {@linkplain ConfigSource#getOrdinal() ordinal} greater than
112   * that of the first, and the result of invoking {@link
113   * String#compareTo(String)} on the return values of the {@link
114   * ConfigSource}s' respective {@link ConfigSource#getName()} methods
115   * otherwise
116   *
117   * @see ConfigSource
118   *
119   * @see ConfigSource#getName()
120   *
121   * @see ConfigSource#getOrdinal()
122   */
123  @Override
124  public final int compare(final ConfigSource firstConfigSource, final ConfigSource secondConfigSource) {
125    final int returnValue;
126    if (firstConfigSource == secondConfigSource) {
127      returnValue = 0;
128    } else if (firstConfigSource == null) {
129      returnValue = 1;
130    } else if (secondConfigSource == null) {
131      returnValue = -1;
132    } else {
133      final int firstOrdinal = firstConfigSource.getOrdinal();
134      final int secondOrdinal = secondConfigSource.getOrdinal();
135      if (firstOrdinal > secondOrdinal) {
136        returnValue = -1;
137      } else if (firstOrdinal < secondOrdinal) {
138        returnValue = 1;
139      } else {
140        final String firstName = firstConfigSource.getName();
141        String secondName = secondConfigSource.getName();
142        if (firstName == null) {
143          if (secondName == null) {
144            returnValue = 0;
145          } else {
146            returnValue = 1;
147          }
148        } else if (secondName == null) {
149          returnValue = -1;
150        } else {
151          returnValue = firstName.compareTo(secondName);
152        }
153      }
154    }
155    return returnValue;
156  }
157
158}