]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java
Modular distributions
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / ExecutionParameterPostProcessor.java
1 package org.argeo.slc.core.execution;
2
3 import java.beans.PropertyDescriptor;
4 import java.util.HashSet;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
12 import org.argeo.slc.SlcException;
13 import org.argeo.slc.execution.ExecutionContext;
14 import org.argeo.slc.execution.ExecutionFlow;
15 import org.springframework.beans.BeansException;
16 import org.springframework.beans.MutablePropertyValues;
17 import org.springframework.beans.PropertyValue;
18 import org.springframework.beans.PropertyValues;
19 import org.springframework.beans.factory.BeanDefinitionStoreException;
20 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
21 import org.springframework.beans.factory.config.TypedStringValue;
22 import org.springframework.beans.factory.support.ManagedList;
23 import org.springframework.beans.factory.support.ManagedMap;
24 import org.springframework.beans.factory.support.ManagedSet;
25 import org.springframework.util.ObjectUtils;
26 import org.springframework.util.StringUtils;
27
28 public class ExecutionParameterPostProcessor extends
29 InstantiationAwareBeanPostProcessorAdapter {
30
31 private final static Log log = LogFactory
32 .getLog(ExecutionParameterPostProcessor.class);
33
34 private ExecutionContext executionContext;
35 private InstantiationManager instantiationManager;
36
37 private String placeholderPrefix = "@{";
38 private String placeholderSuffix = "}";
39 private String nullValue;
40
41 @Override
42 public PropertyValues postProcessPropertyValues(PropertyValues pvs,
43 PropertyDescriptor[] pds, Object bean, String beanName)
44 throws BeansException {
45
46 // TODO: resolve at execution only if scope is execution
47 // TODO: deal with placeholders in RuntimeBeanReference and
48 // RuntimeBeanNameReference
49
50 MutablePropertyValues newPvs = new MutablePropertyValues();
51
52 boolean changesOccured = false;
53
54 for (PropertyValue pv : pvs.getPropertyValues()) {
55 Object convertedValue = resolveValue(beanName, bean, pv.getValue());
56 newPvs.addPropertyValue(new PropertyValue(pv, convertedValue));
57 if (convertedValue != pv.getValue()) {
58 changesOccured = true;
59 }
60 }
61
62 return changesOccured ? newPvs : pvs;
63 }
64
65 @Override
66 public boolean postProcessAfterInstantiation(Object bean, String beanName)
67 throws BeansException {
68 if (bean instanceof ExecutionFlow)
69 instantiationManager.flowInitializationStarted(
70 (ExecutionFlow) bean, beanName);
71 return true;
72 }
73
74 @Override
75 public Object postProcessAfterInitialization(Object bean, String beanName)
76 throws BeansException {
77 if (bean instanceof ExecutionFlow)
78 instantiationManager.flowInitializationFinished(
79 (ExecutionFlow) bean, beanName);
80 return bean;
81 }
82
83 protected String resolvePlaceholder(Object bean, String placeholder) {
84 if (instantiationManager.isInFlowInitialization())
85 return instantiationManager.getInitializingFlowParameter(
86 placeholder).toString();
87
88 else {// execution
89 // next call fail if no execution context available
90 Object obj = executionContext.getVariable(placeholder);
91 if (obj != null) {
92 return obj.toString();
93 }
94 }
95
96 return null;
97 }
98
99 @SuppressWarnings(value = { "unchecked" })
100 public Object resolveValue(String beanName, Object bean, Object value) {
101 if (value instanceof TypedStringValue) {
102 TypedStringValue tsv = (TypedStringValue) value;
103 String originalValue = tsv.getValue();
104
105 String convertedValue = resolveString(beanName, bean, originalValue);
106 return convertedValue.equals(originalValue) ? value
107 : new TypedStringValue(convertedValue);
108 } else if (value instanceof String) {
109 String originalValue = value.toString();
110 String convertedValue = resolveString(beanName, bean, originalValue);
111 return convertedValue.equals(originalValue) ? value
112 : convertedValue;
113 } else if (value instanceof ManagedMap) {
114 Map mapVal = (Map) value;
115
116 Map newContent = new ManagedMap();
117 boolean entriesModified = false;
118 for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) {
119 Map.Entry entry = (Map.Entry) it.next();
120 Object key = entry.getKey();
121 int keyHash = (key != null ? key.hashCode() : 0);
122 Object newKey = resolveValue(beanName, bean, key);
123 int newKeyHash = (newKey != null ? newKey.hashCode() : 0);
124 Object val = entry.getValue();
125 Object newVal = resolveValue(beanName, bean, val);
126 newContent.put(newKey, newVal);
127 entriesModified = entriesModified
128 || (newVal != val || newKey != key || newKeyHash != keyHash);
129 }
130
131 return entriesModified ? newContent : value;
132 } else if (value instanceof ManagedList) {
133 List listVal = (List) value;
134 List newContent = new ManagedList();
135 boolean valueModified = false;
136
137 for (int i = 0; i < listVal.size(); i++) {
138 Object elem = listVal.get(i);
139 Object newVal = resolveValue(beanName, bean, elem);
140 newContent.add(newVal);
141 if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
142 valueModified = true;
143 }
144 }
145 return valueModified ? newContent : value;
146 } else if (value instanceof ManagedSet) {
147 Set setVal = (Set) value;
148 Set newContent = new ManagedSet();
149 boolean entriesModified = false;
150 for (Iterator it = setVal.iterator(); it.hasNext();) {
151 Object elem = it.next();
152 int elemHash = (elem != null ? elem.hashCode() : 0);
153 Object newVal = resolveValue(beanName, bean, elem);
154 int newValHash = (newVal != null ? newVal.hashCode() : 0);
155 newContent.add(newVal);
156 entriesModified = entriesModified
157 || (newVal != elem || newValHash != elemHash);
158 }
159 return entriesModified ? newContent : value;
160 } else {
161 // log.debug(beanName + ": " + value.getClass() + " : " + value);
162 return value;
163 }
164
165 }
166
167 private String resolveString(String beanName, Object bean, String strVal) {
168 String value = parseStringValue(bean, strVal, new HashSet<String>());
169
170 if (value == null)
171 throw new SlcException("Could not resolve placeholder '" + strVal
172 + "' in bean '" + beanName + "'");
173
174 return (value.equals(nullValue) ? null : value);
175 }
176
177 public void setPlaceholderPrefix(String placeholderPrefix) {
178 this.placeholderPrefix = placeholderPrefix;
179 }
180
181 public void setPlaceholderSuffix(String placeholderSuffix) {
182 this.placeholderSuffix = placeholderSuffix;
183 }
184
185 public void setNullValue(String nullValue) {
186 this.nullValue = nullValue;
187 }
188
189 public void setInstantiationManager(
190 InstantiationManager instantiationManager) {
191 this.instantiationManager = instantiationManager;
192 }
193
194 public void setExecutionContext(ExecutionContext executionContext) {
195 this.executionContext = executionContext;
196 }
197
198 //
199 // Following methods hacked from the internals of
200 // PropertyPlaceholderConfigurer
201 //
202
203 protected String parseStringValue(Object bean, String strVal,
204 Set<String> visitedPlaceholders)
205 throws BeanDefinitionStoreException {
206
207 StringBuffer buf = new StringBuffer(strVal);
208
209 int startIndex = strVal.indexOf(placeholderPrefix);
210 while (startIndex != -1) {
211 int endIndex = findPlaceholderEndIndex(buf, startIndex);
212 if (endIndex != -1) {
213 String placeholder = buf.substring(startIndex
214 + placeholderPrefix.length(), endIndex);
215 if (!visitedPlaceholders.add(placeholder)) {
216 throw new BeanDefinitionStoreException(
217 "Circular placeholder reference '" + placeholder
218 + "' in property definitions");
219 }
220 // Recursive invocation, parsing placeholders contained in
221 // the placeholder key.
222 placeholder = parseStringValue(bean, placeholder,
223 visitedPlaceholders);
224 // Now obtain the value for the fully resolved key...
225 String propVal = resolvePlaceholder(bean, placeholder);
226 if (propVal != null) {
227 // Recursive invocation, parsing placeholders contained
228 // in the
229 // previously resolved placeholder value.
230 propVal = parseStringValue(bean, propVal,
231 visitedPlaceholders);
232 buf.replace(startIndex, endIndex
233 + placeholderSuffix.length(), propVal);
234 if (log.isTraceEnabled()) {
235 log.trace("Resolved placeholder '" + placeholder + "'");
236 }
237 startIndex = buf.indexOf(placeholderPrefix, startIndex
238 + propVal.length());
239 } else {
240 throw new BeanDefinitionStoreException(
241 "Could not resolve placeholder '" + placeholder
242 + "'");
243 }
244 visitedPlaceholders.remove(placeholder);
245 } else {
246 startIndex = -1;
247 }
248 }
249
250 return buf.toString();
251 }
252
253 private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
254 int index = startIndex + placeholderPrefix.length();
255 int withinNestedPlaceholder = 0;
256 while (index < buf.length()) {
257 if (StringUtils.substringMatch(buf, index, placeholderSuffix)) {
258 if (withinNestedPlaceholder > 0) {
259 withinNestedPlaceholder--;
260 index = index + placeholderSuffix.length();
261 } else {
262 return index;
263 }
264 } else if (StringUtils
265 .substringMatch(buf, index, placeholderPrefix)) {
266 withinNestedPlaceholder++;
267 index = index + placeholderPrefix.length();
268 } else {
269 index++;
270 }
271 }
272 return -1;
273 }
274
275 }