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.configuration2.spring; 019 020import java.net.URL; 021import java.util.Properties; 022 023import org.apache.commons.configuration2.CompositeConfiguration; 024import org.apache.commons.configuration2.Configuration; 025import org.apache.commons.configuration2.ConfigurationConverter; 026import org.apache.commons.configuration2.builder.fluent.Configurations; 027import org.apache.commons.lang3.ArrayUtils; 028import org.springframework.beans.factory.FactoryBean; 029import org.springframework.beans.factory.InitializingBean; 030import org.springframework.core.io.Resource; 031import org.springframework.util.Assert; 032 033/** 034 * <p>FactoryBean which wraps a Commons CompositeConfiguration object for usage 035 * with PropertiesLoaderSupport. This allows the compositeConfiguration object to behave 036 * like a normal java.util.Properties object which can be passed on to 037 * setProperties() method allowing PropertyOverrideConfigurer and 038 * PropertyPlaceholderConfigurer to take advantage of Commons Configuration. 039 * </p> 040 * <p>Internally a CompositeConfiguration object is used for merging multiple 041 * Configuration objects.</p> 042 * 043 * @see java.util.Properties 044 * @see org.springframework.core.io.support.PropertiesLoaderSupport 045 * 046 */ 047public class ConfigurationPropertiesFactoryBean implements InitializingBean, FactoryBean<Properties> 048{ 049 050 /** internal CompositeConfiguration containing the merged configuration objects **/ 051 private CompositeConfiguration compositeConfiguration; 052 053 /** supplied configurations that will be merged in compositeConfiguration **/ 054 private Configuration[] configurations; 055 056 /** Spring resources for loading configurations **/ 057 private Resource[] locations; 058 059 /** @see org.apache.commons.configuration2.AbstractConfiguration#throwExceptionOnMissing **/ 060 private boolean throwExceptionOnMissing = true; 061 062 public ConfigurationPropertiesFactoryBean() 063 { 064 } 065 066 public ConfigurationPropertiesFactoryBean(final Configuration configuration) 067 { 068 Assert.notNull(configuration, "configuration"); 069 this.compositeConfiguration = new CompositeConfiguration(configuration); 070 } 071 072 /** 073 * @see org.springframework.beans.factory.FactoryBean#getObject() 074 */ 075 @Override 076 public Properties getObject() throws Exception 077 { 078 return compositeConfiguration != null ? ConfigurationConverter.getProperties(compositeConfiguration) : null; 079 } 080 081 /** 082 * @see org.springframework.beans.factory.FactoryBean#getObjectType() 083 */ 084 @Override 085 public Class<?> getObjectType() 086 { 087 return java.util.Properties.class; 088 } 089 090 /** 091 * @see org.springframework.beans.factory.FactoryBean#isSingleton() 092 */ 093 @Override 094 public boolean isSingleton() 095 { 096 return true; 097 } 098 099 /** 100 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 101 */ 102 @Override 103 public void afterPropertiesSet() throws Exception 104 { 105 if (compositeConfiguration == null && ArrayUtils.isEmpty(configurations) && ArrayUtils.isEmpty(locations)) 106 { 107 throw new IllegalArgumentException("no configuration object or location specified"); 108 } 109 110 if (compositeConfiguration == null) 111 { 112 compositeConfiguration = new CompositeConfiguration(); 113 } 114 115 compositeConfiguration.setThrowExceptionOnMissing(throwExceptionOnMissing); 116 117 if (configurations != null) 118 { 119 for (final Configuration configuration : configurations) 120 { 121 compositeConfiguration.addConfiguration(configuration); 122 } 123 } 124 125 if (locations != null) 126 { 127 for (final Resource location : locations) 128 { 129 final URL url = location.getURL(); 130 final Configuration props = new Configurations().properties(url); 131 compositeConfiguration.addConfiguration(props); 132 } 133 } 134 } 135 136 public Configuration[] getConfigurations() 137 { 138 return defensiveCopy(configurations); 139 } 140 141 /** 142 * Set the commons configurations objects which will be used as properties. 143 * 144 * @param configurations commons configurations objects which will be used as properties. 145 */ 146 public void setConfigurations(final Configuration... configurations) 147 { 148 this.configurations = defensiveCopy(configurations); 149 } 150 151 public Resource[] getLocations() 152 { 153 return defensiveCopy(locations); 154 } 155 156 /** 157 * Shortcut for loading compositeConfiguration from Spring resources. It will 158 * internally create a PropertiesConfiguration object based on the URL 159 * retrieved from the given Resources. 160 * 161 * @param locations resources of configuration files 162 */ 163 public void setLocations(final Resource... locations) 164 { 165 this.locations = defensiveCopy(locations); 166 } 167 168 public boolean isThrowExceptionOnMissing() 169 { 170 return throwExceptionOnMissing; 171 } 172 173 /** 174 * Set the underlying Commons CompositeConfiguration throwExceptionOnMissing flag. 175 * 176 * @see org.apache.commons.configuration2.AbstractConfiguration#setThrowExceptionOnMissing(boolean) 177 * @param throwExceptionOnMissing The new value for the property 178 */ 179 public void setThrowExceptionOnMissing(final boolean throwExceptionOnMissing) 180 { 181 this.throwExceptionOnMissing = throwExceptionOnMissing; 182 } 183 184 public CompositeConfiguration getConfiguration() 185 { 186 return compositeConfiguration; 187 } 188 189 /** 190 * Creates a defensive copy of the specified array. Handles null values 191 * correctly. 192 * 193 * @param src the source array 194 * @param <T> the type of the array 195 * @return the defensive copy of the array 196 */ 197 private static <T> T[] defensiveCopy(final T[] src) 198 { 199 return src != null ? src.clone() : null; 200 } 201}