    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.math3.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.math3.exception.MathIllegalArgumentException;
    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 $Id: TransformerMap.java 1416643 2012-12-03 19:37:14Z tn $
    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 MathIllegalArgumentException if the Object can not be
    138         * transformed into a Double.
    139         * @see org.apache.commons.math3.util.NumberTransformer#transform(java.lang.Object)
    140         */
    141        public double transform(Object o) throws MathIllegalArgumentException {
    142            double value = Double.NaN;
    143
    144            if (o instanceof Number || o instanceof String) {
    145                value = defaultTransformer.transform(o);
    146            } else {
    147                NumberTransformer trans = getTransformer(o.getClass());
    148                if (trans != null) {
    149                    value = trans.transform(o);
    150                }
    151            }
    152
    153            return value;
    154        }
    155
    156        /** {@inheritDoc} */
    157        @Override
    158        public boolean equals(Object other) {
    159            if (this == other) {
    160                return true;
    161            }
    162            if (other instanceof TransformerMap) {
    163                TransformerMap rhs = (TransformerMap) other;
    164                if (! defaultTransformer.equals(rhs.defaultTransformer)) {
    165                    return false;
    166                }
    167                if (map.size() != rhs.map.size()) {
    168                    return false;
    169                }
    170                for (Map.Entry<Class<?>, NumberTransformer> entry : map.entrySet()) {
    171                    if (! entry.getValue().equals(rhs.map.get(entry.getKey()))) {
    172                        return false;
    173                    }
    174                }
    175                return true;
    176            }
    177            return false;
    178        }
    179
    180        /** {@inheritDoc} */
    181        @Override
    182        public int hashCode() {
    183            int hash = defaultTransformer.hashCode();
    184            for (NumberTransformer t : map.values()) {
    185                hash = hash * 31 + t.hashCode();
    186            }
    187            return hash;
    188        }
    189
    190    }