    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     */
    017    package org.apache.commons.math.util;
    018
    019    import java.io.Serializable;
    020    import java.util.Collection;
    021    import java.util.HashMap;
    022    import java.util.Map;
    023    import java.util.Set;
    024
    025    import org.apache.commons.math.MathException;
    026
    027    /**
    028     * This TansformerMap automates the transformation of mixed object types.
    029     * It provides a means to set NumberTransformers that will be selected
    030     * based on the Class of the object handed to the Maps
    031     * <code>double transform(Object o)</code> method.
    032     * @version $Revision: 922713 $ $Date: 2010-03-14 02:26:13 +0100 (dim. 14 mars 2010) $
    033     */
    034    public class TransformerMap implements NumberTransformer, Serializable {
    035
    036        /** Serializable version identifier */
    037        private static final long serialVersionUID = 4605318041528645258L;
    038
    039        /**
    040         * A default Number Transformer for Numbers and numeric Strings.
    041         */
    042        private NumberTransformer defaultTransformer = null;
    043
    044        /**
    045         * The internal Map.
    046         */
    047        private Map<Class<?>, NumberTransformer> map = null;
    048
    049        /**
    050         * Build a map containing only the default transformer.
    051         */
    052        public TransformerMap() {
    053            map = new HashMap<Class<?>, NumberTransformer>();
    054            defaultTransformer = new DefaultTransformer();
    055        }
    056
    057        /**
    058         * Tests if a Class is present in the TransformerMap.
    059         * @param key Class to check
    060         * @return true|false
    061         */
    062        public boolean containsClass(Class<?> key) {
    063            return map.containsKey(key);
    064        }
    065
    066        /**
    067         * Tests if a NumberTransformer is present in the TransformerMap.
    068         * @param value NumberTransformer to check
    069         * @return true|false
    070         */
    071        public boolean containsTransformer(NumberTransformer value) {
    072            return map.containsValue(value);
    073        }
    074
    075        /**
    076         * Returns the Transformer that is mapped to a class
    077         * if mapping is not present, this returns null.
    078         * @param key The Class of the object
    079         * @return the mapped NumberTransformer or null.
    080         */
    081        public NumberTransformer getTransformer(Class<?> key) {
    082            return map.get(key);
    083        }
    084
    085        /**
    086         * Sets a Class to Transformer Mapping in the Map. If
    087         * the Class is already present, this overwrites that
    088         * mapping.
    089         * @param key The Class
    090         * @param transformer The NumberTransformer
    091         * @return the replaced transformer if one is present
    092         */
    093        public NumberTransformer putTransformer(Class<?> key, NumberTransformer transformer) {
    094            return map.put(key, transformer);
    095        }
    096
    097        /**
    098         * Removes a Class to Transformer Mapping in the Map.
    099         * @param key The Class
    100         * @return the removed transformer if one is present or
    101         * null if none was present.
    102         */
    103        public NumberTransformer removeTransformer(Class<?> key) {
    104            return map.remove(key);
    105        }
    106
    107        /**
    108         * Clears all the Class to Transformer mappings.
    109         */
    110        public void clear() {
    111            map.clear();
    112        }
    113
    114        /**
    115         * Returns the Set of Classes used as keys in the map.
    116         * @return Set of Classes
    117         */
    118        public Set<Class<?>> classes() {
    119            return map.keySet();
    120        }
    121
    122        /**
    123         * Returns the Set of NumberTransformers used as values
    124         * in the map.
    125         * @return Set of NumberTransformers
    126         */
    127        public Collection<NumberTransformer> transformers() {
    128            return map.values();
    129        }
    130
    131        /**
    132         * Attempts to transform the Object against the map of
    133         * NumberTransformers. Otherwise it returns Double.NaN.
    134         *
    135         * @param o the Object to be transformed.
    136         * @return the double value of the Object.
    137         * @throws MathException if the Object can not be transformed into a Double.
    138         * @see org.apache.commons.math.util.NumberTransformer#transform(java.lang.Object)
    139         */
    140        public double transform(Object o) throws MathException {
    141            double value = Double.NaN;
    142
    143            if (o instanceof Number || o instanceof String) {
    144                value = defaultTransformer.transform(o);
    145            } else {
    146                NumberTransformer trans = getTransformer(o.getClass());
    147                if (trans != null) {
    148                    value = trans.transform(o);
    149                }
    150            }
    151
    152            return value;
    153        }
    154
    155        /** {@inheritDoc} */
    156        @Override
    157        public boolean equals(Object other) {
    158            if (this == other) {
    159                return true;
    160            }
    161            if (other instanceof TransformerMap) {
    162                TransformerMap rhs = (TransformerMap) other;
    163                if (! defaultTransformer.equals(rhs.defaultTransformer)) {
    164                    return false;
    165                }
    166                if (map.size() != rhs.map.size()) {
    167                    return false;
    168                }
    169                for (Map.Entry<Class<?>, NumberTransformer> entry : map.entrySet()) {
    170                    if (! entry.getValue().equals(rhs.map.get(entry.getKey()))) {
    171                        return false;
    172                    }
    173                }
    174                return true;
    175            }
    176            return false;
    177        }
    178
    179        /** {@inheritDoc} */
    180        @Override
    181        public int hashCode() {
    182            int hash = defaultTransformer.hashCode();
    183            for (NumberTransformer t : map.values()) {
    184                hash = hash * 31 + t.hashCode();
    185            }
    186            return hash;
    187        }
    188
    189    }