org.eclipse.gemini.blueprint.test.internal.util.PropertiesUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gemini.blueprint.test.internal.util.PropertiesUtil.java

Source

/******************************************************************************
 * Copyright (c) 2006, 2010 VMware Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution. 
 * The Eclipse Public License is available at 
 * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
 * is available at http://www.opensource.org/licenses/apache2.0.php.
 * You may elect to redistribute this code under either of these licenses. 
 * 
 * Contributors:
 *   VMware Inc.
 *****************************************************************************/

package org.eclipse.gemini.blueprint.test.internal.util;

import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Loads a property file performing key expansion.
 * 
 * Provides simple property substitution, without support for inner or nested placeholders. Also, the algorithm does
 * only one parsing so derivative placeholders are not supported.
 * 
 * 
 * @author Costin Leau
 * 
 */
public abstract class PropertiesUtil {

    private static final String DELIM_START = "${";

    private static final String DELIM_STOP = "}";

    private static final Properties EMPTY_PROPERTIES = new Properties();

    private static final class OrderedProperties extends Properties implements Cloneable {

        private final Map<Object, Object> map = new LinkedHashMap<Object, Object>();

        /**
         * 
         * @see java.util.Map#clear()
         */
        public void clear() {
            map.clear();
        }

        /**
         * @param key
         * @return
         * @see java.util.Map#containsKey(java.lang.Object)
         */
        public boolean containsKey(Object key) {
            return map.containsKey(key);
        }

        /**
         * @param value
         * @return
         * @see java.util.Map#containsValue(java.lang.Object)
         */
        public boolean containsValue(Object value) {
            return map.containsValue(value);
        }

        /**
         * @return
         * @see java.util.Map#entrySet()
         */
        public Set<Entry<Object, Object>> entrySet() {
            return map.entrySet();
        }

        /**
         * @param o
         * @return
         * @see java.util.Map#equals(java.lang.Object)
         */
        public boolean equals(Object o) {
            return map.equals(o);
        }

        /**
         * @param key
         * @return
         * @see java.util.Map#get(java.lang.Object)
         */
        public Object get(Object key) {
            return map.get(key);
        }

        @Override
        public String getProperty(String key) {
            Object oval = map.get(key);
            String sval = (oval instanceof String) ? (String) oval : null;
            return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
        }

        /**
         * @return
         * @see java.util.Map#hashCode()
         */
        public int hashCode() {
            return map.hashCode();
        }

        /**
         * @return
         * @see java.util.Map#isEmpty()
         */
        public boolean isEmpty() {
            return map.isEmpty();
        }

        /**
         * @return
         * @see java.util.Map#keySet()
         */
        public Set<Object> keySet() {
            return map.keySet();
        }

        /**
         * @param key
         * @param value
         * @return
         * @see java.util.Map#put(java.lang.Object, java.lang.Object)
         */
        public Object put(Object key, Object value) {
            return map.put(key, value);
        }

        /**
         * @param m
         * @see java.util.Map#putAll(java.util.Map)
         */
        public void putAll(Map<? extends Object, ? extends Object> m) {
            map.putAll(m);
        }

        /**
         * @param key
         * @return
         * @see java.util.Map#remove(java.lang.Object)
         */
        public Object remove(Object key) {
            return map.remove(key);
        }

        /**
         * @return
         * @see java.util.Map#size()
         */
        public int size() {
            return map.size();
        }

        /**
         * @return
         * @see java.util.Map#values()
         */
        public Collection<Object> values() {
            return map.values();
        }

        @Override
        public synchronized boolean contains(Object value) {
            return map.containsValue(value);
        }

        @Override
        public synchronized Enumeration<Object> elements() {
            return new IteratorBackedEnumeration(map.values().iterator());
        }

        @Override
        public synchronized Enumeration<Object> keys() {
            return new IteratorBackedEnumeration(map.keySet().iterator());
        }

        @Override
        public synchronized String toString() {
            return map.toString();
        }

        private final class IteratorBackedEnumeration<K> implements Enumeration<K> {

            private final Iterator<? extends K> iterator;

            public IteratorBackedEnumeration(Iterator<? extends K> iterator) {
                this.iterator = iterator;
            }

            public boolean hasMoreElements() {
                return iterator.hasNext();
            }

            public K nextElement() {
                return iterator.next();
            }
        }
    }

    /**
     * Shortcut method - loads a property object from the given input stream and applies property expansion. The
     * returned properties object preserves order at the expense of speed.
     * 
     * @param resource
     * @return
     */
    public static Properties loadAndExpand(Resource resource) {
        Properties props = new OrderedProperties();

        if (resource == null)
            return props;

        try {
            props.load(resource.getInputStream());
        } catch (IOException ex) {
            return null;
        }
        return expandProperties(props);
    }

    /**
     * Filter/Eliminate keys that start with the given prefix.
     * 
     * @param properties
     * @param prefix
     * @return
     */
    public static Properties filterKeysStartingWith(Properties properties, String prefix) {
        if (!StringUtils.hasText(prefix))
            return EMPTY_PROPERTIES;

        Assert.notNull(properties);

        Properties excluded = (properties instanceof OrderedProperties ? new OrderedProperties()
                : new Properties());

        // filter ignore keys out
        for (Enumeration enm = properties.keys(); enm.hasMoreElements();) {
            String key = (String) enm.nextElement();
            if (key.startsWith(prefix)) {
                excluded.put(key, properties.get(key));
            }
        }

        for (Enumeration enm = excluded.keys(); enm.hasMoreElements();) {
            properties.remove(enm.nextElement());
        }
        return excluded;
    }

    /**
     * Filter/Eliminate keys that have a value that starts with the given prefix.
     * 
     * @param properties
     * @param prefix
     * @return
     */
    public static Properties filterValuesStartingWith(Properties properties, String prefix) {
        if (!StringUtils.hasText(prefix))
            return EMPTY_PROPERTIES;

        Assert.notNull(properties);
        Properties excluded = (properties instanceof OrderedProperties ? new OrderedProperties()
                : new Properties());

        for (Enumeration enm = properties.keys(); enm.hasMoreElements();) {
            String key = (String) enm.nextElement();
            String value = properties.getProperty(key);
            if (value.startsWith(prefix)) {
                excluded.put(key, value);
            }
        }

        for (Enumeration enm = excluded.keys(); enm.hasMoreElements();) {
            properties.remove(enm.nextElement());
        }
        return excluded;
    }

    /**
     * Apply placeholder expansion to the given properties object.
     * 
     * Will return a new properties object, containing the expanded entries. Note that both keys and values will be
     * expanded.
     * 
     * @param props
     * @return
     */
    public static Properties expandProperties(Properties props) {
        Assert.notNull(props);

        Set entrySet = props.entrySet();

        Properties newProps = (props instanceof OrderedProperties ? new OrderedProperties() : new Properties());

        for (Iterator iter = entrySet.iterator(); iter.hasNext();) {
            // first expand the keys
            Map.Entry entry = (Map.Entry) iter.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();

            String resultKey = expandProperty(key, props);
            String resultValue = expandProperty(value, props);

            // replace old entry

            newProps.put(resultKey, resultValue);
        }

        return newProps;
    }

    private static String expandProperty(String prop, Properties properties) throws IllegalArgumentException {

        boolean hasPlaceholder = false;
        String copy = prop;

        StringBuilder result = new StringBuilder();

        int index = 0;
        // dig out the placeholders
        do {
            index = copy.indexOf(DELIM_START);
            if (index >= 0) {
                hasPlaceholder = true;

                // add stuff before the delimiter
                result.append(copy.substring(0, index));
                // remove the delimiter
                copy = copy.substring(index + DELIM_START.length());
                // find ending delim
                int stopIndex = copy.indexOf(DELIM_STOP);
                String token = null;

                if (stopIndex >= 0) {
                    // discover token
                    token = copy.substring(0, stopIndex);
                    // remove ending delimiter
                    copy = copy.substring(stopIndex + 1);
                    // append the replacement for the token
                    result.append(properties.getProperty(token));
                }

                else
                    throw new IllegalArgumentException(
                            "cannot interpret property " + prop + " due of token [" + copy + "]");

            } else {
                hasPlaceholder = false;
                // make sure to append the remaining string
                result.append(copy);
            }

        } while (hasPlaceholder);

        return result.toString();
    }
}