001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.config; 018 019import java.io.IOException; 020import java.util.Enumeration; 021import java.util.Properties; 022 023import org.springframework.beans.BeansException; 024import org.springframework.beans.factory.BeanInitializationException; 025import org.springframework.core.Ordered; 026import org.springframework.core.PriorityOrdered; 027import org.springframework.core.io.support.PropertiesLoaderSupport; 028import org.springframework.util.ObjectUtils; 029 030/** 031 * Allows for configuration of individual bean property values from a property resource, 032 * i.e. a properties file. Useful for custom config files targeted at system 033 * administrators that override bean properties configured in the application context. 034 * 035 * <p>Two concrete implementations are provided in the distribution: 036 * <ul> 037 * <li>{@link PropertyOverrideConfigurer} for "beanName.property=value" style overriding 038 * (<i>pushing</i> values from a properties file into bean definitions) 039 * <li>{@link PropertyPlaceholderConfigurer} for replacing "${...}" placeholders 040 * (<i>pulling</i> values from a properties file into bean definitions) 041 * </ul> 042 * 043 * <p>Property values can be converted after reading them in, through overriding 044 * the {@link #convertPropertyValue} method. For example, encrypted values 045 * can be detected and decrypted accordingly before processing them. 046 * 047 * @author Juergen Hoeller 048 * @since 02.10.2003 049 * @see PropertyOverrideConfigurer 050 * @see PropertyPlaceholderConfigurer 051 */ 052public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport 053 implements BeanFactoryPostProcessor, PriorityOrdered { 054 055 private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered 056 057 058 /** 059 * Set the order value of this object for sorting purposes. 060 * @see PriorityOrdered 061 */ 062 public void setOrder(int order) { 063 this.order = order; 064 } 065 066 @Override 067 public int getOrder() { 068 return this.order; 069 } 070 071 072 /** 073 * {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and 074 * {@linkplain #processProperties process} properties against the given bean factory. 075 * @throws BeanInitializationException if any properties cannot be loaded 076 */ 077 @Override 078 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 079 try { 080 Properties mergedProps = mergeProperties(); 081 082 // Convert the merged properties, if necessary. 083 convertProperties(mergedProps); 084 085 // Let the subclass process the properties. 086 processProperties(beanFactory, mergedProps); 087 } 088 catch (IOException ex) { 089 throw new BeanInitializationException("Could not load properties", ex); 090 } 091 } 092 093 /** 094 * Convert the given merged properties, converting property values 095 * if necessary. The result will then be processed. 096 * <p>The default implementation will invoke {@link #convertPropertyValue} 097 * for each property value, replacing the original with the converted value. 098 * @param props the Properties to convert 099 * @see #processProperties 100 */ 101 protected void convertProperties(Properties props) { 102 Enumeration<?> propertyNames = props.propertyNames(); 103 while (propertyNames.hasMoreElements()) { 104 String propertyName = (String) propertyNames.nextElement(); 105 String propertyValue = props.getProperty(propertyName); 106 String convertedValue = convertProperty(propertyName, propertyValue); 107 if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) { 108 props.setProperty(propertyName, convertedValue); 109 } 110 } 111 } 112 113 /** 114 * Convert the given property from the properties source to the value 115 * which should be applied. 116 * <p>The default implementation calls {@link #convertPropertyValue(String)}. 117 * @param propertyName the name of the property that the value is defined for 118 * @param propertyValue the original value from the properties source 119 * @return the converted value, to be used for processing 120 * @see #convertPropertyValue(String) 121 */ 122 protected String convertProperty(String propertyName, String propertyValue) { 123 return convertPropertyValue(propertyValue); 124 } 125 126 /** 127 * Convert the given property value from the properties source to the value 128 * which should be applied. 129 * <p>The default implementation simply returns the original value. 130 * Can be overridden in subclasses, for example to detect 131 * encrypted values and decrypt them accordingly. 132 * @param originalValue the original value from the properties source 133 * (properties file or local "properties") 134 * @return the converted value, to be used for processing 135 * @see #setProperties 136 * @see #setLocations 137 * @see #setLocation 138 * @see #convertProperty(String, String) 139 */ 140 protected String convertPropertyValue(String originalValue) { 141 return originalValue; 142 } 143 144 145 /** 146 * Apply the given Properties to the given BeanFactory. 147 * @param beanFactory the BeanFactory used by the application context 148 * @param props the Properties to apply 149 * @throws org.springframework.beans.BeansException in case of errors 150 */ 151 protected abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) 152 throws BeansException; 153 154}