View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.configuration.beanutils;
19  
20  import java.lang.reflect.Array;
21  import java.util.Collection;
22  import java.util.List;
23  
24  import org.apache.commons.beanutils.DynaBean;
25  import org.apache.commons.beanutils.DynaClass;
26  import org.apache.commons.configuration.Configuration;
27  import org.apache.commons.configuration.ConfigurationMap;
28  import org.apache.commons.configuration.SubsetConfiguration;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  
32  /**
33   * The <tt>ConfigurationDynaBean</tt> dynamically reads and writes
34   * configurations properties from a wrapped configuration-collection
35   * {@link org.apache.commons.configuration.Configuration} instance. It also
36   * implements a {@link java.util.Map} interface so that it can be used in
37   * JSP 2.0 Expression Language expressions.
38   *
39   * <p>The {@code ConfigurationDynaBean} maps nested and mapped properties
40   * to the appropriate {@code Configuration} subset using the
41   * {@link org.apache.commons.configuration.Configuration#subset}
42   * method. Similarly, indexed properties reference lists of configuration
43   * properties using the
44   * {@link org.apache.commons.configuration.Configuration#getList(String)}
45   * method. Setting an indexed property is supported, too.</p>
46   *
47   * <p>Note: Some of the methods expect that a dot (&quot;.&quot;) is used as
48   * property delimiter for the wrapped configuration. This is true for most of
49   * the default configurations. Hierarchical configurations, for which a specific
50   * expression engine is set, may cause problems.</p>
51   *
52   * @author <a href="mailto:ricardo.gladwell@btinternet.com">Ricardo Gladwell</a>
53   * @version $Id: ConfigurationDynaBean.java 1366932 2012-07-29 20:06:31Z oheger $
54   * @since 1.0-rc1
55   */
56  public class ConfigurationDynaBean extends ConfigurationMap implements DynaBean
57  {
58      /** Constant for the property delimiter.*/
59      private static final String PROPERTY_DELIMITER = ".";
60  
61      /** The logger.*/
62      private static final Log LOG = LogFactory.getLog(ConfigurationDynaBean.class);
63  
64      /**
65       * Creates a new instance of {@code ConfigurationDynaBean} and sets
66       * the configuration this bean is associated with.
67       *
68       * @param configuration the configuration
69       */
70      public ConfigurationDynaBean(Configuration configuration)
71      {
72          super(configuration);
73          if (LOG.isTraceEnabled())
74          {
75              LOG.trace("ConfigurationDynaBean(" + configuration + ")");
76          }
77      }
78  
79      public void set(String name, Object value)
80      {
81          if (LOG.isTraceEnabled())
82          {
83              LOG.trace("set(" + name + "," + value + ")");
84          }
85  
86          if (value == null)
87          {
88              throw new NullPointerException("Error trying to set property to null.");
89          }
90  
91          if (value instanceof Collection)
92          {
93              Collection<?> collection = (Collection<?>) value;
94              for (Object v : collection)
95              {
96                  getConfiguration().addProperty(name, v);
97              }
98          }
99          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 }