    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.lang3.text;
    018
    019    import java.util.Map;
    020
    021    /**
    022     * Lookup a String key to a String value.
    023     * <p>
    024     * This class represents the simplest form of a string to string map.
    025     * It has a benefit over a map in that it can create the result on
    026     * demand based on the key.
    027     * <p>
    028     * This class comes complete with various factory methods.
    029     * If these do not suffice, you can subclass and implement your own matcher.
    030     * <p>
    031     * For example, it would be possible to implement a lookup that used the
    032     * key as a primary key, and looked up the value on demand from the database
    033     *
    034     * @author Apache Software Foundation
    035     * @since 2.2
    036     * @version $Id: StrLookup.java 899933 2010-01-16 12:53:54Z sebb $
    037     */
    038    public abstract class StrLookup<V> {
    039
    040        /**
    041         * Lookup that always returns null.
    042         */
    043        private static final StrLookup<String> NONE_LOOKUP;
    044        /**
    045         * Lookup that uses System properties.
    046         */
    047        private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP;
    048        static {
    049            NONE_LOOKUP = new MapStrLookup<String>(null);
    050            StrLookup<String> lookup = null;
    051            try {
    052                final Map<?, ?> propMap = System.getProperties();
    053                @SuppressWarnings("unchecked") // System property keys and values are always Strings
    054                final Map<String, String> properties = (Map<String, String>) propMap;
    055                lookup = new MapStrLookup<String>(properties);
    056            } catch (SecurityException ex) {
    057                lookup = NONE_LOOKUP;
    058            }
    059            SYSTEM_PROPERTIES_LOOKUP = lookup;
    060        }
    061
    062        //-----------------------------------------------------------------------
    063        /**
    064         * Returns a lookup which always returns null.
    065         *
    066         * @return a lookup that always returns null, not null
    067         */
    068        public static StrLookup<?> noneLookup() {
    069            return NONE_LOOKUP;
    070        }
    071
    072        /**
    073         * Returns a lookup which uses {@link System#getProperties() System properties}
    074         * to lookup the key to value.
    075         * <p>
    076         * If a security manager blocked access to system properties, then null will
    077         * be returned from every lookup.
    078         * <p>
    079         * If a null key is used, this lookup will throw a NullPointerException.
    080         *
    081         * @return a lookup using system properties, not null
    082         */
    083        public static StrLookup<String> systemPropertiesLookup() {
    084            return SYSTEM_PROPERTIES_LOOKUP;
    085        }
    086
    087        /**
    088         * Returns a lookup which looks up values using a map.
    089         * <p>
    090         * If the map is null, then null will be returned from every lookup.
    091         * The map result object is converted to a string using toString().
    092         *
    093         * @param map  the map of keys to values, may be null
    094         * @return a lookup using the map, not null
    095         */
    096        public static <V> StrLookup<V> mapLookup(Map<String, V> map) {
    097            return new MapStrLookup<V>(map);
    098        }
    099
    100        //-----------------------------------------------------------------------
    101        /**
    102         * Constructor.
    103         */
    104        protected StrLookup() {
    105            super();
    106        }
    107
    108        /**
    109         * Looks up a String key to a String value.
    110         * <p>
    111         * The internal implementation may use any mechanism to return the value.
    112         * The simplest implementation is to use a Map. However, virtually any
    113         * implementation is possible.
    114         * <p>
    115         * For example, it would be possible to implement a lookup that used the
    116         * key as a primary key, and looked up the value on demand from the database
    117         * Or, a numeric based implementation could be created that treats the key
    118         * as an integer, increments the value and return the result as a string -
    119         * converting 1 to 2, 15 to 16 etc.
    120         * <p>
    121         * The {@link #lookup(String)} method always returns a String, regardless of
    122         * the underlying data, by converting it as necessary. For example:
    123         * <pre>
    124         * Map<String, Object> map = new HashMap<String, Object>();
    125         * map.put("number", new Integer(2));
    126         * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
    127         * </pre>
    128         * @param key  the key to be looked up, may be null
    129         * @return the matching value, null if no match
    130         */
    131        public abstract String lookup(String key);
    132
    133        //-----------------------------------------------------------------------
    134        /**
    135         * Lookup implementation that uses a Map.
    136         */
    137        static class MapStrLookup<V> extends StrLookup<V> {
    138
    139            /** Map keys are variable names and value. */
    140            private final Map<String, V> map;
    141
    142            /**
    143             * Creates a new instance backed by a Map.
    144             *
    145             * @param map  the map of keys to values, may be null
    146             */
    147            MapStrLookup(Map<String, V> map) {
    148                this.map = map;
    149            }
    150
    151            /**
    152             * Looks up a String key to a String value using the map.
    153             * <p>
    154             * If the map is null, then null is returned.
    155             * The map result object is converted to a string using toString().
    156             *
    157             * @param key  the key to be looked up, may be null
    158             * @return the matching value, null if no match
    159             */
    160            @Override
    161            public String lookup(String key) {
    162                if (map == null) {
    163                    return null;
    164                }
    165                Object obj = map.get(key);
    166                if (obj == null) {
    167                    return null;
    168                }
    169                return obj.toString();
    170            }
    171        }
    172    }