    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.configuration;
    018
    019    import java.lang.reflect.Method;
    020    import java.util.Collection;
    021    import java.util.HashMap;
    022    import java.util.Iterator;
    023    import java.util.Map;
    024
    025    import org.apache.commons.lang.SystemUtils;
    026    import org.apache.tools.ant.taskdefs.Execute;
    027
    028    /**
    029     * <p>
    030     * A Configuration implementation that reads the platform specific environment
    031     * variables. On pre java5 JRE it uses Ant Execute task to read the environment.
    032     * (in this case ant must be present in classpath). On java >= 5 JRE it uses
    033     * <code>java.lang.System#getenv()</code> and ant is not required.
    034     * </p>
    035     * <p>
    036     * This configuration implementation is read-only. It allows read access to the
    037     * defined OS environment variables, but their values cannot be changed.
    038     * </p>
    039     * <p>
    040     * Usage of this class is easy: After an instance has been created the get
    041     * methods provided by the <code>Configuration</code> interface can be used
    042     * for querying environment variables, e.g.:
    043     *
    044     * <pre>
    045     * Configuration envConfig = new EnvironmentConfiguration();
    046     * System.out.println("JAVA_HOME=" + envConfig.getString("JAVA_HOME");
    047     * </pre>
    048     *
    049     * </p>
    050     *
    051     * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
    052     * @see org.apache.tools.ant.taskdefs.Execute#getProcEnvironment()
    053     * @since 1.5
    054     */
    055    public class EnvironmentConfiguration extends AbstractConfiguration
    056    {
    057        /** Constant for the name of the getenv() method. */
    058        private static final String METHOD_NAME = "getenv";
    059
    060        /** Constant for the Java version 1.5. */
    061        private static final int VERSION_1_5 = 150;
    062
    063        /** Stores the environment properties. */
    064        private Map environment;
    065
    066        /**
    067         * Constructor.
    068         */
    069        public EnvironmentConfiguration()
    070        {
    071            if (SystemUtils.isJavaVersionAtLeast(VERSION_1_5))
    072            {
    073                extractProperties15();
    074            }
    075            else
    076            {
    077                extractProperties14();
    078            }
    079        }
    080
    081        /**
    082         * Adds a property to this configuration. Because this configuration is
    083         * read-only, this operation is not allowed and will cause an exception.
    084         *
    085         * @param key the key of the property to be added
    086         * @param value the property value
    087         */
    088        protected void addPropertyDirect(String key, Object value)
    089        {
    090            throw new UnsupportedOperationException("Configuration is read-only!");
    091        }
    092
    093        /**
    094         * {@inheritDoc}
    095         *
    096         * @see org.apache.commons.configuration.AbstractConfiguration#containsKey(java.lang.String)
    097         */
    098        public boolean containsKey(String key)
    099        {
    100            return environment.containsKey(key);
    101        }
    102
    103        /**
    104         * {@inheritDoc}
    105         *
    106         * @see org.apache.commons.configuration.AbstractConfiguration#getKeys()
    107         */
    108        public Iterator getKeys()
    109        {
    110            return environment.keySet().iterator();
    111        }
    112
    113        /**
    114         * {@inheritDoc}
    115         *
    116         * @see org.apache.commons.configuration.AbstractConfiguration#getProperty(java.lang.String)
    117         */
    118        public Object getProperty(String key)
    119        {
    120            return environment.get(key);
    121        }
    122
    123        /**
    124         * {@inheritDoc}
    125         *
    126         * @see org.apache.commons.configuration.AbstractConfiguration#isEmpty()
    127         */
    128        public boolean isEmpty()
    129        {
    130            return environment.isEmpty();
    131        }
    132
    133        /**
    134         * Removes a property from this configuration. Because this configuration is
    135         * read-only, this operation is not allowed and will cause an exception.
    136         *
    137         * @param key the key of the property to be removed
    138         */
    139        public void clearProperty(String key)
    140        {
    141            throw new UnsupportedOperationException("Configuration is read-only!");
    142        }
    143
    144        /**
    145         * Removes all properties from this configuration. Because this
    146         * configuration is read-only, this operation is not allowed and will cause
    147         * an exception.
    148         */
    149        public void clear()
    150        {
    151            throw new UnsupportedOperationException("Configuration is read-only!");
    152        }
    153
    154        /**
    155         * Extracts environment properties on a JRE &lt; 1.5. This implementation
    156         * uses ant for this purpose.
    157         */
    158        void extractProperties14()
    159        {
    160            extractPropertiesFromCollection(Execute.getProcEnvironment());
    161        }
    162
    163        /**
    164         * An internally used method for processing a collection with environment
    165         * entries. The collection must contain strings like
    166         * <code>property=value</code>. Such a collection is returned by ant.
    167         *
    168         * @param env the collection with the properties
    169         */
    170        void extractPropertiesFromCollection(Collection env)
    171        {
    172            environment = new HashMap();
    173            for (Iterator it = env.iterator(); it.hasNext();)
    174            {
    175                String entry = (String) it.next();
    176                int pos = entry.indexOf('=');
    177                if (pos == -1)
    178                {
    179                    getLogger().warn("Ignoring: " + entry);
    180                }
    181                else
    182                {
    183                    environment.put(entry.substring(0, pos), entry
    184                            .substring(pos + 1));
    185                }
    186            }
    187        }
    188
    189        /**
    190         * Extracts environment properties on a JR &gt;= 1.5. From this Java version
    191         * on, there is an official way of doing this. However because the code
    192         * should compile on lower Java versions, too, we have to invoke the method
    193         * using reflection.
    194         */
    195        void extractProperties15()
    196        {
    197            try
    198            {
    199                Method method = System.class.getMethod(METHOD_NAME, null);
    200                environment = (Map) method.invoke(null, null);
    201            }
    202            catch (Exception ex)
    203            {
    204                // this should normally not happen on a JRE >= 1.5
    205                throw new ConfigurationRuntimeException(
    206                        "Error when accessing environment properties", ex);
    207            }
    208        }
    209    }