    001    // Copyright 2006, 2007, 2008, 2010, 2011, 2012 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
    015    package org.apache.tapestry5.ioc.services;
    016
    017    import org.apache.tapestry5.plastic.PlasticUtils;
    018
    019    /**
    020     * An immutable object that represents a mapping from one type to another. This is also the contribution type when
    021     * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
    022     * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
    023     * describe
    024     * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
    025     * coercions).
    026     *
    027     * @param <S>
    028     *         source (input) type
    029     * @param <T>
    030     *         target (output) type
    031     */
    032    public final class CoercionTuple<S, T>
    033    {
    034        private final Class<S> sourceType;
    035
    036        private final Class<T> targetType;
    037
    038        private final Coercion<S, T> coercion;
    039
    040        /**
    041         * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
    042         */
    043        private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
    044        {
    045            private final Coercion<WS, WT> coercion;
    046
    047            public CoercionWrapper(Coercion<WS, WT> coercion)
    048            {
    049                this.coercion = coercion;
    050            }
    051
    052            public WT coerce(WS input)
    053            {
    054                return coercion.coerce(input);
    055            }
    056
    057            @Override
    058            public String toString()
    059            {
    060                return String.format("%s --> %s", convert(sourceType), convert(targetType));
    061            }
    062        }
    063
    064        private String convert(Class type)
    065        {
    066            if (Void.class.equals(type))
    067                return "null";
    068
    069            String name = PlasticUtils.toTypeName(type);
    070
    071            int dotx = name.lastIndexOf('.');
    072
    073            // Strip off a package name of "java.lang"
    074
    075            if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
    076                return name.substring(dotx + 1);
    077
    078            return name;
    079        }
    080
    081        /**
    082         * Standard constructor, which defaults wrap to true.
    083         */
    084        public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
    085        {
    086            this(sourceType, targetType, coercion, true);
    087        }
    088
    089        /**
    090         * Convenience constructor to help with generics.
    091         *
    092         * @since 5.2.0
    093         */
    094        public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
    095        {
    096            return new CoercionTuple<S, T>(sourceType, targetType, coercion);
    097        }
    098
    099        /**
    100         * Internal-use constructor.
    101         *
    102         * @param sourceType
    103         *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
    104         * @param targetType
    105         *         the target (or output) type of the coercion
    106         * @param coercion
    107         *         the object that performs the coercion
    108         * @param wrap
    109         *         if true, the coercion is wrapped to provide a useful toString()
    110         */
    111        @SuppressWarnings("unchecked")
    112        public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
    113        {
    114            assert sourceType != null;
    115            assert targetType != null;
    116            assert coercion != null;
    117
    118            this.sourceType = PlasticUtils.toWrapperType(sourceType);
    119            this.targetType = PlasticUtils.toWrapperType(targetType);
    120            this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
    121        }
    122
    123        @Override
    124        public String toString()
    125        {
    126            return coercion.toString();
    127        }
    128
    129        public Coercion<S, T> getCoercion()
    130        {
    131            return coercion;
    132        }
    133
    134        public Class<S> getSourceType()
    135        {
    136            return sourceType;
    137        }
    138
    139        public Class<T> getTargetType()
    140        {
    141            return targetType;
    142        }
    143
    144    }