001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2015-2016 ForgeRock AS.
015 */
016package org.forgerock.util;
017
018import java.util.Comparator;
019
020/**
021 * Ordered pair of arbitrary objects. Use of Pair is strictly restricted to internal (non-public) APIs:<br>
022 * - Pair cannot be used in public APIs
023 * - Consider using dedicated classes over Pair. Dedicated classes are more readable while Pair is meaningless.<br>
024 * - Pair should only be used to return two values from a method, just like a tuple. If you need more than two
025 * values, create a dedicated class.
026 *
027 * @param <F>
028 *            type of the first pair element
029 * @param <S>
030 *            type of the second pair element
031 */
032public final class Pair<F, S> {
033
034    private static final class ComparablePairComparator
035            <F extends Comparable<F>, S extends Comparable<S>>
036            implements Comparator<Pair<F, S>> {
037        /** {@inheritDoc} */
038        @Override
039        public int compare(Pair<F, S> o1, Pair<F, S> o2) {
040            final int compareResult = o1.getFirst().compareTo(o2.getFirst());
041            if (compareResult == 0) {
042                return o1.getSecond().compareTo(o2.getSecond());
043            }
044            return compareResult;
045        }
046    }
047
048    /** An empty Pair. */
049    public static final Pair<?, ?> EMPTY = Pair.of(null, null);
050
051    /**
052     * {@link Comparator} for {@link Pair}s made of {@link Comparable} elements.
053     */
054    @SuppressWarnings("rawtypes")
055    public static final Comparator COMPARATOR = new ComparablePairComparator();
056
057    /** The first pair element. */
058    private final F first;
059
060    /** The second pair element. */
061    private final S second;
062
063    /**
064     * Creates a pair.
065     *
066     * @param first
067     *            the first element of the constructed pair
068     * @param second
069     *            the second element of the constructed pair
070     */
071    private Pair(F first, S second) {
072        this.first = first;
073        this.second = second;
074    }
075
076    /**
077     * Creates a new {@code Pair}.
078     *
079     * @param first
080     *            the first element of the constructed pair
081     * @param second
082     *            the second element of the constructed pair
083     * @param <F>
084     *            type of the first pair element
085     * @param <S>
086     *            type of the second pair element
087     * @return A new Pair built with the provided elements
088     */
089    public static <F, S> Pair<F, S> of(F first, S second) {
090        return new Pair<>(first, second);
091    }
092
093    /**
094     * Returns an empty Pair matching the required types.
095     *
096     * @param <F>
097     *            type of the first pair element
098     * @param <S>
099     *            type of the second pair element
100     * @return An empty Pair matching the required types
101     */
102    @SuppressWarnings("unchecked")
103    public static <F, S> Pair<F, S> empty() {
104        return (Pair<F, S>) EMPTY;
105    }
106
107    /**
108     * Returns a comparator for Pairs of comparable objects.
109     *
110     * @param <F>
111     *            type of the first pair element
112     * @param <S>
113     *            type of the second pair element
114     * @return a comparator for Pairs of comparable objects.
115     */
116    @SuppressWarnings("unchecked")
117    public static <F extends Comparable<F>, S extends Comparable<S>> Comparator<Pair<F, S>> getPairComparator() {
118        return COMPARATOR;
119    }
120
121    /**
122     * Returns the first element of this pair.
123     *
124     * @return the first element of this pair
125     */
126    public F getFirst() {
127        return first;
128    }
129
130    /**
131     * Returns the second element of this pair.
132     *
133     * @return the second element of this pair
134     */
135    public S getSecond() {
136        return second;
137    }
138
139    /** {@inheritDoc} */
140    @Override
141    public int hashCode() {
142        final int prime = 31;
143        int result = 1;
144        result = prime * result + ((first == null) ? 0 : first.hashCode());
145        result = prime * result + ((second == null) ? 0 : second.hashCode());
146        return result;
147    }
148
149    /** {@inheritDoc} */
150    @Override
151    public boolean equals(Object obj) {
152        if (this == obj) {
153            return true;
154        }
155
156        if (!(obj instanceof Pair)) {
157            return false;
158        }
159
160        Pair<?, ?> other = (Pair<?, ?>) obj;
161        if (first == null) {
162            if (other.first != null) {
163                return false;
164            }
165        } else if (!first.equals(other.first)) {
166            return false;
167        }
168
169        if (second == null) {
170            if (other.second != null) {
171                return false;
172            }
173        } else {
174            return second.equals(other.second);
175        }
176
177        return true;
178    }
179
180    /** {@inheritDoc} */
181    @Override
182    public String toString() {
183        return "Pair [" + first + ", " + second + "]";
184    }
185}