    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
    018    package org.apache.commons.configuration.beanutils;
    019
    020    import java.lang.reflect.Array;
    021    import java.util.Collection;
    022    import java.util.List;
    023
    024    import org.apache.commons.beanutils.DynaBean;
    025    import org.apache.commons.beanutils.DynaClass;
    026    import org.apache.commons.configuration.Configuration;
    027    import org.apache.commons.configuration.ConfigurationMap;
    028    import org.apache.commons.configuration.SubsetConfiguration;
    029    import org.apache.commons.logging.Log;
    030    import org.apache.commons.logging.LogFactory;
    031
    032    /**
    033     * The <tt>ConfigurationDynaBean</tt> dynamically reads and writes
    034     * configurations properties from a wrapped configuration-collection
    035     * {@link org.apache.commons.configuration.Configuration} instance. It also
    036     * implements a {@link java.util.Map} interface so that it can be used in
    037     * JSP 2.0 Expression Language expressions.
    038     *
    039     * <p>The {@code ConfigurationDynaBean} maps nested and mapped properties
    040     * to the appropriate {@code Configuration} subset using the
    041     * {@link org.apache.commons.configuration.Configuration#subset}
    042     * method. Similarly, indexed properties reference lists of configuration
    043     * properties using the
    044     * {@link org.apache.commons.configuration.Configuration#getList(String)}
    045     * method. Setting an indexed property is supported, too.</p>
    046     *
    047     * <p>Note: Some of the methods expect that a dot (&quot;.&quot;) is used as
    048     * property delimiter for the wrapped configuration. This is true for most of
    049     * the default configurations. Hierarchical configurations, for which a specific
    050     * expression engine is set, may cause problems.</p>
    051     *
    052     * @author <a href="mailto:ricardo.gladwell@btinternet.com">Ricardo Gladwell</a>
    053     * @version $Id: ConfigurationDynaBean.java 1208765 2011-11-30 20:41:50Z oheger $
    054     * @since 1.0-rc1
    055     */
    056    public class ConfigurationDynaBean extends ConfigurationMap implements DynaBean
    057    {
    058        /** Constant for the property delimiter.*/
    059        private static final String PROPERTY_DELIMITER = ".";
    060
    061        /** The logger.*/
    062        private static Log log = LogFactory.getLog(ConfigurationDynaBean.class);
    063
    064        /**
    065         * Creates a new instance of {@code ConfigurationDynaBean} and sets
    066         * the configuration this bean is associated with.
    067         *
    068         * @param configuration the configuration
    069         */
    070        public ConfigurationDynaBean(Configuration configuration)
    071        {
    072            super(configuration);
    073            if (log.isTraceEnabled())
    074            {
    075                log.trace("ConfigurationDynaBean(" + configuration + ")");
    076            }
    077        }
    078
    079        public void set(String name, Object value)
    080        {
    081            if (log.isTraceEnabled())
    082            {
    083                log.trace("set(" + name + "," + value + ")");
    084            }
    085
    086            if (value == null)
    087            {
    088                throw new NullPointerException("Error trying to set property to null.");
    089            }
    090
    091            if (value instanceof Collection)
    092            {
    093                Collection<?> collection = (Collection<?>) value;
    094                for (Object v : collection)
    095                {
    096                    getConfiguration().addProperty(name, v);
    097                }
    098            }
    099            else if (value.getClass().isArray())
    100            {
    101                int length = Array.getLength(value);
    102                for (int i = 0; i < length; i++)
    103                {
    104                    getConfiguration().addProperty(name, Array.get(value, i));
    105                }
    106            }
    107            else
    108            {
    109                getConfiguration().setProperty(name, value);
    110            }
    111        }
    112
    113        public Object get(String name)
    114        {
    115            if (log.isTraceEnabled())
    116            {
    117                log.trace("get(" + name + ")");
    118            }
    119
    120            // get configuration property
    121            Object result = getConfiguration().getProperty(name);
    122            if (result == null)
    123            {
    124                // otherwise attempt to create bean from configuration subset
    125                Configuration subset = new SubsetConfiguration(getConfiguration(), name, PROPERTY_DELIMITER);
    126                if (!subset.isEmpty())
    127                {
    128                    result = new ConfigurationDynaBean(subset);
    129                }
    130            }
    131
    132            if (log.isDebugEnabled())
    133            {
    134                log.debug(name + "=[" + result + "]");
    135            }
    136
    137            if (result == null)
    138            {
    139                throw new IllegalArgumentException("Property '" + name + "' does not exist.");
    140            }
    141            return result;
    142        }
    143
    144        public boolean contains(String name, String key)
    145        {
    146            Configuration subset = getConfiguration().subset(name);
    147            if (subset == null)
    148            {
    149                throw new IllegalArgumentException("Mapped property '" + name + "' does not exist.");
    150            }
    151
    152            return subset.containsKey(key);
    153        }
    154
    155        public Object get(String name, int index)
    156        {
    157            if (!checkIndexedProperty(name))
    158            {
    159                throw new IllegalArgumentException("Property '" + name
    160                        + "' is not indexed.");
    161            }
    162
    163            List<Object> list = getConfiguration().getList(name);
    164            return list.get(index);
    165        }
    166
    167        public Object get(String name, String key)
    168        {
    169            Configuration subset = getConfiguration().subset(name);
    170            if (subset == null)
    171            {
    172                throw new IllegalArgumentException("Mapped property '" + name + "' does not exist.");
    173            }
    174
    175            return subset.getProperty(key);
    176        }
    177
    178        public DynaClass getDynaClass()
    179        {
    180            return new ConfigurationDynaClass(getConfiguration());
    181        }
    182
    183        public void remove(String name, String key)
    184        {
    185            Configuration subset = new SubsetConfiguration(getConfiguration(), name, PROPERTY_DELIMITER);
    186            subset.setProperty(key, null);
    187        }
    188
    189        public void set(String name, int index, Object value)
    190        {
    191            if (!checkIndexedProperty(name) && index > 0)
    192            {
    193                throw new IllegalArgumentException("Property '" + name
    194                        + "' is not indexed.");
    195            }
    196
    197            Object property = getConfiguration().getProperty(name);
    198
    199            if (property instanceof List)
    200            {
    201                // This is safe because multiple values of a configuration property
    202                // are always stored as lists of type Object.
    203                @SuppressWarnings("unchecked")
    204                List<Object> list = (List<Object>) property;
    205                list.set(index, value);
    206                getConfiguration().setProperty(name, list);
    207            }
    208            else if (property.getClass().isArray())
    209            {
    210                Array.set(property, index, value);
    211            }
    212            else if (index == 0)
    213            {
    214                getConfiguration().setProperty(name, value);
    215            }
    216        }
    217
    218        public void set(String name, String key, Object value)
    219        {
    220            getConfiguration().setProperty(name + "." + key, value);
    221        }
    222
    223        /**
    224         * Tests whether the given name references an indexed property. This
    225         * implementation tests for properties of type list or array. If the
    226         * property does not exist, an exception is thrown.
    227         *
    228         * @param name the name of the property to check
    229         * @return a flag whether this is an indexed property
    230         * @throws IllegalArgumentException if the property does not exist
    231         */
    232        private boolean checkIndexedProperty(String name)
    233        {
    234            Object property = getConfiguration().getProperty(name);
    235
    236            if (property == null)
    237            {
    238                throw new IllegalArgumentException("Property '" + name
    239                        + "' does not exist.");
    240            }
    241
    242            return (property instanceof List) || property.getClass().isArray();
    243        }
    244    }