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 License.
004 *
005 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
006 * specific language governing permission and limitations under the License.
007 *
008 * When distributing Covered Software, include this CDDL Header Notice in each file and include
009 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
010 * Header, with the fields enclosed by brackets [] replaced by your own identifying
011 * information: "Portions copyright [year] [name of copyright owner]".
012 *
013 * Copyright 2015 ForgeRock AS.
014 */
015package org.forgerock.util;
016
017import java.util.Comparator;
018
019/**
020 * Ordered pair of arbitrary objects. Use of Pair is strictly restricted to internal (non-public) APIs:<br>
021 * - Pair cannot be used in public APIs
022 * - Consider using dedicated classes over Pair. Dedicated classes are more readable while Pair is meaningless.<br>
023 * - Pair should only be used to return two values from a method, just like a tuple. If you need more than two
024 * values, create a dedicated class.
025 *
026 * @param <F>
027 *            type of the first pair element
028 * @param <S>
029 *            type of the second pair element
030 */
031public final class Pair<F, S> {
032
033    private static final class ComparablePairComparator
034            <F extends Comparable<F>, S extends Comparable<S>>
035            implements Comparator<Pair<F, S>> {
036        /** {@inheritDoc} */
037        @Override
038        public int compare(Pair<F, S> o1, Pair<F, S> o2) {
039            final int compareResult = o1.getFirst().compareTo(o2.getFirst());
040            if (compareResult == 0) {
041                return o1.getSecond().compareTo(o2.getSecond());
042            }
043            return compareResult;
044        }
045    }
046
047    /** An empty Pair. */
048    public static final Pair<?, ?> EMPTY = Pair.of(null, null);
049
050    /**
051     * {@link Comparator} for {@link Pair}s made of {@link Comparable} elements.
052     */
053    @SuppressWarnings("rawtypes")
054    public static final Comparator COMPARATOR = new ComparablePairComparator();
055
056    /** The first pair element. */
057    private final F first;
058
059    /** The second pair element. */
060    private final S second;
061
062    /**
063     * Creates a pair.
064     *
065     * @param first
066     *            the first element of the constructed pair
067     * @param second
068     *            the second element of the constructed pair
069     */
070    private Pair(F first, S second) {
071        this.first = first;
072        this.second = second;
073    }
074
075    /**
076     * Creates a new {@code Pair}
077     *
078     * @param first
079     *            the first element of the constructed pair
080     * @param second
081     *            the second element of the constructed pair
082     * @param <F>
083     *            type of the first pair element
084     * @param <S>
085     *            type of the second pair element
086     * @return A new Pair built with the provided elements
087     */
088    public static <F, S> Pair<F, S> of(F first, S second) {
089        return new Pair<>(first, second);
090    }
091
092    /**
093     * Returns an empty Pair matching the required types.
094     *
095     * @param <F>
096     *            type of the first pair element
097     * @param <S>
098     *            type of the second pair element
099     * @return An empty Pair matching the required types
100     */
101    @SuppressWarnings("unchecked")
102    public static <F, S> Pair<F, S> empty() {
103        return (Pair<F, S>) EMPTY;
104    }
105
106    /**
107     * Returns a comparator for Pairs of comparable objects.
108     *
109     * @param <F>
110     *            type of the first pair element
111     * @param <S>
112     *            type of the second pair element
113     * @return a comparator for Pairs of comparable objects.
114     */
115    @SuppressWarnings("unchecked")
116    public static <F extends Comparable<F>, S extends Comparable<S>>
117    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}