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 (".") 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 }