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