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 018package org.apache.commons.configuration.beanutils; 019 020import java.lang.reflect.Array; 021import java.util.Collection; 022import java.util.List; 023 024import org.apache.commons.beanutils.DynaBean; 025import org.apache.commons.beanutils.DynaClass; 026import org.apache.commons.configuration.Configuration; 027import org.apache.commons.configuration.ConfigurationMap; 028import org.apache.commons.configuration.SubsetConfiguration; 029import org.apache.commons.logging.Log; 030import 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 (".") 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 1366932 2012-07-29 20:06:31Z oheger $ 054 * @since 1.0-rc1 055 */ 056public 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 final 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}