    001// Copyright 2010 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.func;
    016
    017/**
    018 * A Tuple holds two values of two different types.
    019 *
    020 * @param <A>
    021 * @param <B>
    022 * @since 5.3
    023 */
    024public class Tuple<A, B>
    025{
    026    public final A first;
    027
    028    public final B second;
    029
    030    public Tuple(A first, B second)
    031    {
    032        this.first = first;
    033        this.second = second;
    034    }
    035
    036    public static <X, Y> Tuple<X, Y> create(X first, Y second)
    037    {
    038        return new Tuple<X, Y>(first, second);
    039    }
    040
    041    /**
    042     * Returns the values of the tuple, separated by commas, enclosed in parenthesis. Example:
    043     * <code>("Ace", "Spades")</code>.
    044     */
    045    @Override
    046    public String toString()
    047    {
    048        StringBuilder builder = new StringBuilder("(");
    049
    050        builder.append(String.valueOf(first));
    051        builder.append(", ");
    052        builder.append(String.valueOf(second));
    053
    054        extendDescription(builder);
    055
    056        return builder.append(')').toString();
    057    }
    058
    059    /**
    060     * Overriden in subclasses to write additional values into the
    061     * description.
    062     *
    063     * @param builder
    064     */
    065    protected void extendDescription(StringBuilder builder)
    066    {
    067    }
    068
    069    /** Utility for comparing two values, either of which may be null. */
    070    static boolean isEqual(Object left, Object right)
    071    {
    072        return left == right || (left != null && left.equals(right));
    073    }
    074
    075    /**
    076     * Compares this Tuple to another object. Equality is defined by: other object is not null,
    077     * is same class as this Tuple, and all values are themselves equal.
    078     */
    079    @Override
    080    public boolean equals(Object obj)
    081    {
    082        if (obj == this)
    083            return true;
    084
    085        if (obj == null || !(obj.getClass() == getClass()))
    086            return false;
    087
    088        return isMatch(obj);
    089    }
    090
    091    /**
    092     * The heart of {@link #equals(Object)}; the other object is the same class as this object.
    093     *
    094     * @param other
    095     *            other tuple to compare
    096     * @return true if all values stored in tuple match
    097     */
    098    protected boolean isMatch(Object other)
    099    {
    100        Tuple<?, ?> tuple = (Tuple<?, ?>) other;
    101
    102        return isEqual(first, tuple.first) && isEqual(second, tuple.second);
    103    }
    104}