001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.tuple;
018
019import java.io.Serializable;
020
021import org.apache.commons.lang3.ObjectUtils;
022import org.apache.commons.lang3.builder.CompareToBuilder;
023
024/**
025 * <p>A triple consisting of three elements.</p>
026 *
027 * <p>This class is an abstract implementation defining the basic API.
028 * It refers to the elements as 'left', 'middle' and 'right'.</p>
029 *
030 * <p>Subclass implementations may be mutable or immutable.
031 * However, there is no restriction on the type of the stored objects that may be stored.
032 * If mutable objects are stored in the triple, then the triple itself effectively becomes mutable.</p>
033 *
034 * @param <L> the left element type
035 * @param <M> the middle element type
036 * @param <R> the right element type
037 *
038 * @version $Id: Triple.java 1557584 2014-01-12 18:26:49Z britter $
039 * @since 3.2
040 */
041public abstract class Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {
042
043    /** Serialization version */
044    private static final long serialVersionUID = 1L;
045
046    /**
047     * <p>Obtains an immutable triple of from three objects inferring the generic types.</p>
048     *
049     * <p>This factory allows the triple to be created using inference to
050     * obtain the generic types.</p>
051     *
052     * @param <L> the left element type
053     * @param <M> the middle element type
054     * @param <R> the right element type
055     * @param left  the left element, may be null
056     * @param middle the middle element, may be null
057     * @param right  the right element, may be null
058     * @return a triple formed from the three parameters, not null
059     */
060    public static <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {
061        return new ImmutableTriple<L, M, R>(left, middle, right);
062    }
063
064    //-----------------------------------------------------------------------
065    /**
066     * <p>Gets the left element from this triple.</p>
067     *
068     * @return the left element, may be null
069     */
070    public abstract L getLeft();
071
072    /**
073     * <p>Gets the middle element from this triple.</p>
074     *
075     * @return the middle element, may be null
076     */
077    public abstract M getMiddle();
078
079    /**
080     * <p>Gets the right element from this triple.</p>
081     *
082     * @return the right element, may be null
083     */
084    public abstract R getRight();
085
086    //-----------------------------------------------------------------------
087    /**
088     * <p>Compares the triple based on the left element, followed by the middle element,
089     * finally the right element.
090     * The types must be {@code Comparable}.</p>
091     *
092     * @param other  the other triple, not null
093     * @return negative if this is less, zero if equal, positive if greater
094     */
095    @Override
096    public int compareTo(final Triple<L, M, R> other) {
097      return new CompareToBuilder().append(getLeft(), other.getLeft())
098          .append(getMiddle(), other.getMiddle())
099          .append(getRight(), other.getRight()).toComparison();
100    }
101
102    /**
103     * <p>Compares this triple to another based on the three elements.</p>
104     *
105     * @param obj  the object to compare to, null returns false
106     * @return true if the elements of the triple are equal
107     */
108    @SuppressWarnings( "deprecation" ) // ObjectUtils.equals(Object, Object) has been deprecated in 3.2
109    @Override
110    public boolean equals(final Object obj) {
111        if (obj == this) {
112            return true;
113        }
114        if (obj instanceof Triple<?, ?, ?>) {
115            final Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
116            return ObjectUtils.equals(getLeft(), other.getLeft())
117                && ObjectUtils.equals(getMiddle(), other.getMiddle())
118                && ObjectUtils.equals(getRight(), other.getRight());
119        }
120        return false;
121    }
122
123    /**
124     * <p>Returns a suitable hash code.</p>
125     *
126     * @return the hash code
127     */
128    @Override
129    public int hashCode() {
130        return (getLeft() == null ? 0 : getLeft().hashCode()) ^
131            (getMiddle() == null ? 0 : getMiddle().hashCode()) ^
132            (getRight() == null ? 0 : getRight().hashCode());
133    }
134
135    /**
136     * <p>Returns a String representation of this triple using the format {@code ($left,$middle,$right)}.</p>
137     *
138     * @return a string describing this object, not null
139     */
140    @Override
141    public String toString() {
142        return new StringBuilder().append('(').append(getLeft()).append(',').append(getMiddle()).append(',')
143            .append(getRight()).append(')').toString();
144    }
145
146    /**
147     * <p>Formats the receiver using the given format.</p>
148     *
149     * <p>This uses {@link java.util.Formattable} to perform the formatting. Three variables may
150     * be used to embed the left and right elements. Use {@code %1$s} for the left
151     * element, {@code %2$s} for the middle and {@code %3$s} for the right element.
152     * The default format used by {@code toString()} is {@code (%1$s,%2$s,%3$s)}.</p>
153     *
154     * @param format  the format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null
155     * @return the formatted string, not null
156     */
157    public String toString(final String format) {
158        return String.format(format, getLeft(), getMiddle(), getRight());
159    }
160
161}
162