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}