1 /*
2 * The contents of this file are subject to the terms of the Common Development and
3 * Distribution License (the License). You may not use this file except in compliance with the
4 * License.
5 *
6 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7 * specific language governing permission and limitations under the License.
8 *
9 * When distributing Covered Software, include this CDDL Header Notice in each file and include
10 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11 * Header, with the fields enclosed by brackets [] replaced by your own identifying
12 * information: "Portions copyright [year] [name of copyright owner]".
13 *
14 * Copyright 2015-2016 ForgeRock AS.
15 */
16 package org.forgerock.util;
17
18 import java.util.Comparator;
19
20 /**
21 * Ordered pair of arbitrary objects. Use of Pair is strictly restricted to internal (non-public) APIs:<br>
22 * - Pair cannot be used in public APIs
23 * - Consider using dedicated classes over Pair. Dedicated classes are more readable while Pair is meaningless.<br>
24 * - Pair should only be used to return two values from a method, just like a tuple. If you need more than two
25 * values, create a dedicated class.
26 *
27 * @param <F>
28 * type of the first pair element
29 * @param <S>
30 * type of the second pair element
31 */
32 public final class Pair<F, S> {
33
34 private static final class ComparablePairComparator
35 <F extends Comparable<F>, S extends Comparable<S>>
36 implements Comparator<Pair<F, S>> {
37 /** {@inheritDoc} */
38 @Override
39 public int compare(Pair<F, S> o1, Pair<F, S> o2) {
40 final int compareResult = o1.getFirst().compareTo(o2.getFirst());
41 if (compareResult == 0) {
42 return o1.getSecond().compareTo(o2.getSecond());
43 }
44 return compareResult;
45 }
46 }
47
48 /** An empty Pair. */
49 public static final Pair<?, ?> EMPTY = Pair.of(null, null);
50
51 /**
52 * {@link Comparator} for {@link Pair}s made of {@link Comparable} elements.
53 */
54 @SuppressWarnings("rawtypes")
55 public static final Comparator COMPARATOR = new ComparablePairComparator();
56
57 /** The first pair element. */
58 private final F first;
59
60 /** The second pair element. */
61 private final S second;
62
63 /**
64 * Creates a pair.
65 *
66 * @param first
67 * the first element of the constructed pair
68 * @param second
69 * the second element of the constructed pair
70 */
71 private Pair(F first, S second) {
72 this.first = first;
73 this.second = second;
74 }
75
76 /**
77 * Creates a new {@code Pair}.
78 *
79 * @param first
80 * the first element of the constructed pair
81 * @param second
82 * the second element of the constructed pair
83 * @param <F>
84 * type of the first pair element
85 * @param <S>
86 * type of the second pair element
87 * @return A new Pair built with the provided elements
88 */
89 public static <F, S> Pair<F, S> of(F first, S second) {
90 return new Pair<>(first, second);
91 }
92
93 /**
94 * Returns an empty Pair matching the required types.
95 *
96 * @param <F>
97 * type of the first pair element
98 * @param <S>
99 * 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 }