1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.reactive.beans.factory.config;
18
19 import org.springframework.beans.factory.config.*;
20 import org.springframework.beans.factory.BeanNameAware;
21 import org.springframework.beans.factory.BeanFactoryAware;
22 import org.springframework.beans.factory.BeanFactory;
23 import org.springframework.beans.factory.BeanDefinitionStoreException;
24 import org.springframework.beans.BeansException;
25 import org.springframework.beans.MutablePropertyValues;
26 import org.springframework.beans.PropertyValue;
27 import org.springframework.core.Ordered;
28 import org.springframework.util.ObjectUtils;
29
30 import java.util.*;
31
32
33 /***
34 * Allows for configuration of individual bean property values from a configuration resource.
35 *
36 * <p>Note: This class is based heavily on the org.springframework.beans.factory.config.PropertyPlaceholderConfigurer by Juergen Hoeller</p>
37 *
38 * @author Dan Washusen
39 * @version $Id: ConfigurationPlaceholderProcessor.java,v 1.1 2004/12/26 23:42:29 dan_washusen Exp $
40 * @since 16.12.2004
41 */
42 public class ConfigurationPlaceholderProcessor
43 implements BeanFactoryPostProcessor, Ordered, BeanNameAware, BeanFactoryAware {
44 /*** The position in the set of BeanFactoryPostProcessor that this will be processed in */
45 private int order = Integer.MAX_VALUE;
46 /*** The beans name as defined in the bean factory */
47 private String beanName;
48 /*** The bean factory itself */
49 private BeanFactory beanFactory;
50 /*** Used to evaluate placeholders with their actual values */
51 protected PlaceholderEvaluator placeholderEvaluator;
52 /*** Used to determine if the value from the bean factory requires evaluation. By default {@link DefaultPlaceholderMatcher} is used. */
53 protected PlaceholderMatcher placeholderMatcher = new DefaultPlaceholderMatcher();
54
55 public int getOrder() {
56 return order;
57 }
58
59 public void setOrder(int order) {
60 this.order = order;
61 }
62
63 public String getBeanName() {
64 return beanName;
65 }
66
67 public void setBeanName(String beanName) {
68 this.beanName = beanName;
69 }
70
71 public BeanFactory getBeanFactory() {
72 return beanFactory;
73 }
74
75 public void setBeanFactory(BeanFactory beanFactory)
76 throws BeansException {
77 this.beanFactory = beanFactory;
78 }
79
80 /***
81 * Returns the implementation of {@link PlaceholderEvaluator} used to evaluate placeholder values.
82 * @return The place holder eveluator
83 */
84 public PlaceholderEvaluator getPlaceholderEvaluator() {
85 return placeholderEvaluator;
86 }
87
88 /***
89 * Sets the implementation of {@link PlaceholderEvaluator} used to evaluate placeholder values.
90 * @param placeholderEvaluator The place holder eveluator
91 */
92 public void setPlaceholderEvaluator(PlaceholderEvaluator placeholderEvaluator) {
93 this.placeholderEvaluator = placeholderEvaluator;
94 }
95
96 /***
97 * Returns the implementation of {@link PlaceholderMatcher} used to determine if a value requires evalutation.
98 * @return The place holder matcher
99 */
100 public PlaceholderMatcher getPlaceholderMatcher() {
101 return placeholderMatcher;
102 }
103
104 /***
105 * Sets the implementation of {@link PlaceholderMatcher} used to determine if a value requires evalutation.
106 * @param placeholderEvaluator The place holder matcher
107 */
108 public void setPlaceholderMatcher(PlaceholderMatcher placeholderMatcher) {
109 this.placeholderMatcher = placeholderMatcher;
110 }
111
112 /***
113 * Processes the bean definitions available in the provided ConfigurableListableBeanFactory.
114 * <p>This method ensures it does not process itself or other bean factories.</p>
115 * @param configurableListableBeanFactory The bean factory to process.
116 * @throws BeansException If an error occurrs while processing a bean definition
117 */
118 public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
119 throws BeansException {
120
121 String[] beanNames = configurableListableBeanFactory.getBeanDefinitionNames();
122 for (int i = 0; i < beanNames.length; i++) {
123
124
125 if (!(beanNames[i].equals(getBeanName()) && configurableListableBeanFactory.equals(getBeanFactory()))) {
126 BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(beanNames[i]);
127
128 try {
129 processBeanDefinition(beanDefinition);
130 }
131 catch (BeanDefinitionStoreException e) {
132 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanNames[i], e.getMessage(), e);
133 }
134 }
135 }
136 }
137
138 /***
139 * Process a single bean definition, processing the property values, indexed argument and generic argument contrsuctor values if there are any.
140 * @param beanDefinition The bean definition to be processed
141 */
142 protected void processBeanDefinition(BeanDefinition beanDefinition) {
143
144 MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();
145 if (mutablePropertyValues != null) {
146 processPropertyValues(beanDefinition.getPropertyValues());
147 }
148
149
150 ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
151 if (constructorArgumentValues != null) {
152 processConstructorArgumentValues(constructorArgumentValues.getIndexedArgumentValues().values());
153 processConstructorArgumentValues(constructorArgumentValues.getGenericArgumentValues());
154 }
155 }
156
157 /***
158 * Process the property values.
159 * @param mutablePropertyValues The mutable property values
160 */
161 protected void processPropertyValues(MutablePropertyValues mutablePropertyValues) {
162 PropertyValue[] propertyValues = mutablePropertyValues.getPropertyValues();
163
164
165 for (int i = 0; i < propertyValues.length; i++) {
166 PropertyValue propertyValue = propertyValues[i];
167
168 Object parsedValue = processValue(propertyValue.getValue());
169
170
171 if (!ObjectUtils.nullSafeEquals(parsedValue, propertyValue.getValue())) {
172 mutablePropertyValues.addPropertyValue(propertyValue.getName(), parsedValue);
173 }
174 }
175 }
176
177 /***
178 * Process the constructor argument values.
179 * @param genericArgumentValues the constructor argument values
180 */
181 protected void processConstructorArgumentValues(Collection genericArgumentValues) {
182
183 for (Iterator it = genericArgumentValues.iterator(); it.hasNext();) {
184 ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder) it.next();
185
186 Object parsedValue = processValue(valueHolder.getValue());
187
188
189 if (!ObjectUtils.nullSafeEquals(parsedValue, valueHolder.getValue())) {
190 valueHolder.setValue(parsedValue);
191 }
192 }
193 }
194
195 /***
196 * Parses the value by delegating to a more appropriate parse method.
197 * @param value The value to be parsed
198 * @return The parsed value
199 */
200 protected Object processValue(Object value) {
201 if (value instanceof String) {
202 return processString((String) value);
203 }
204 else if (value instanceof RuntimeBeanReference) {
205 RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) value;
206
207 Object parsedBeanName = processString(runtimeBeanReference.getBeanName());
208
209
210 if (!(parsedBeanName instanceof String))
211 throw new InvalidPlaceholderException("Runtime bean reference of name '" + runtimeBeanReference.getBeanName() + "' has been evaluated and it doesn't appear to be an instance of String.");
212
213 if (!parsedBeanName.equals(runtimeBeanReference.getBeanName())) {
214 return new RuntimeBeanReference((String) parsedBeanName);
215 }
216 }
217 else if (value instanceof List) {
218 processList((List) value);
219 }
220 else if (value instanceof Set) {
221 processSet((Set) value);
222 }
223 else if (value instanceof Map) {
224 processMap((Map) value);
225 }
226 else if (value instanceof BeanDefinition) {
227 processBeanDefinition((BeanDefinition) value);
228 }
229 else if (value instanceof BeanDefinitionHolder) {
230 processBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
231 }
232
233 return value;
234 }
235
236 /***
237 * This is the root of all parsing. In the end everything (should) evaluate down to a String. Here, if the
238 * {@link #getPlaceholderMatcher() placeholder matcher} confirms that value needs evaluating, we look up the
239 * value using the {@link #getPlaceholderEvaluator() evaluator} and return the matching object.
240 * @param value The value to the evaluated
241 * @return The object returned from the evaluator if the value was evaluated, otherwise the original value
242 */
243 protected Object processString(String value) {
244
245 PlaceholderMatcher placeholderMatcher = getPlaceholderMatcher();
246 placeholderMatcher.init(value);
247
248
249 if (!placeholderMatcher.isPlaceholderPresent())
250 return value;
251
252
253
254
255 if (placeholderMatcher.isMultiplePlaceholdersPresent()) {
256 StringBuffer evaluatedValueBuffer = new StringBuffer();
257 while (placeholderMatcher.hasNext()) {
258
259 String proceedingText = placeholderMatcher.getProceedingText();
260 if (proceedingText != null)
261 evaluatedValueBuffer.append(proceedingText);
262
263
264 Placeholder placeholder = placeholderMatcher.next();
265
266
267 if (placeholder.getType() != String.class)
268 throw new InvalidPlaceholderException("A value that contains more than one place holder must contain all strings.");
269
270 Object evaluatedValue = getPlaceholderEvaluator().evaluate(placeholder);
271 evaluatedValueBuffer.append(evaluatedValue);
272 }
273
274
275 String trailingText = placeholderMatcher.getTrailingText();
276 if (trailingText != null)
277 evaluatedValueBuffer.append(trailingText);
278
279 return evaluatedValueBuffer.toString();
280 }
281
282 else {
283
284 placeholderMatcher.hasNext();
285 Placeholder placeholder = placeholderMatcher.next();
286 return getPlaceholderEvaluator().evaluate(placeholder);
287 }
288 }
289
290 /***
291 * Parse the given List, resolving its values if necessary.
292 * @param listValue The list to be evaluated
293 */
294 protected void processList(List listValue) {
295 for (int i = 0; i < listValue.size(); i++) {
296 Object element = listValue.get(i);
297
298 Object parsedValue = processValue(element);
299
300
301 if (!ObjectUtils.nullSafeEquals(parsedValue, element)) {
302 listValue.set(i, parsedValue);
303 }
304 }
305 }
306
307 /***
308 * Parse the given Set, resolving its values if necessary.
309 * @param setValue The set to be evaluated
310 */
311 protected void processSet(Set setValue) {
312 for (Iterator iterator = new HashSet(setValue).iterator(); iterator.hasNext();) {
313 Object element = iterator.next();
314
315 Object parsedValue = processValue(element);
316
317
318 if (!ObjectUtils.nullSafeEquals(parsedValue, element)) {
319 setValue.remove(element);
320 setValue.add(parsedValue);
321 }
322 }
323 }
324
325 /***
326 * Parse the given Map, resolving its values if necessary.
327 * @param mapValue The map to be evaluated
328 */
329 protected void processMap(Map mapValue) {
330 for (Iterator iterator = mapValue.entrySet().iterator(); iterator.hasNext();) {
331 Map.Entry entry = (Map.Entry) iterator.next();
332
333 Object parsedKey = processValue(entry.getKey());
334
335 boolean isNewKey = !ObjectUtils.nullSafeEquals(entry.getKey(), parsedKey);
336
337 Object parsedValue = processValue(entry.getValue());
338
339
340 if (isNewKey) {
341 mapValue.remove(entry.getKey());
342 }
343
344
345 if (isNewKey || !ObjectUtils.nullSafeEquals(parsedValue, entry.getValue())) {
346 mapValue.put(parsedKey, parsedValue);
347 }
348 }
349 }
350 }