]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java
5b28534ba43063ceedf61849c9a1f836ecc5ef17
[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 log.debug("Bean class: " + bean.getClass());
90 // next call fail if no execution context available
91 Object obj = executionContext.getVariable(placeholder);
92 if (obj != null) {
93 return obj.toString();
94 }
95 }
96
97 return null;
98 }
99
100 @SuppressWarnings(value = { "unchecked" })
101 public Object resolveValue(String beanName, Object bean, Object value) {
102 if (value instanceof TypedStringValue) {
103 TypedStringValue tsv = (TypedStringValue) value;
104 String originalValue = tsv.getValue();
105
106 String convertedValue = resolveString(beanName, bean, originalValue);
107 return convertedValue.equals(originalValue) ? value
108 : new TypedStringValue(convertedValue);
109 } else if (value instanceof String) {
110 String originalValue = value.toString();
111 String convertedValue = resolveString(beanName, bean, originalValue);
112 return convertedValue.equals(originalValue) ? value
113 : convertedValue;
114 } else if (value instanceof ManagedMap) {
115 Map mapVal = (Map) value;
116
117 Map newContent = new ManagedMap();
118 boolean entriesModified = false;
119 for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) {
120 Map.Entry entry = (Map.Entry) it.next();
121 Object key = entry.getKey();
122 int keyHash = (key != null ? key.hashCode() : 0);
123 Object newKey = resolveValue(beanName, bean, key);
124 int newKeyHash = (newKey != null ? newKey.hashCode() : 0);
125 Object val = entry.getValue();
126 Object newVal = resolveValue(beanName, bean, val);
127 newContent.put(newKey, newVal);
128 entriesModified = entriesModified
129 || (newVal != val || newKey != key || newKeyHash != keyHash);
130 }
131
132 return entriesModified ? newContent : value;
133 } else if (value instanceof ManagedList) {
134 List listVal = (List) value;
135 List newContent = new ManagedList();
136 boolean valueModified = false;
137
138 for (int i = 0; i < listVal.size(); i++) {
139 Object elem = listVal.get(i);
140 Object newVal = resolveValue(beanName, bean, elem);
141 newContent.add(newVal);
142 if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
143 valueModified = true;
144 }
145 }
146 return valueModified ? newContent : value;
147 } else if (value instanceof ManagedSet) {
148 Set setVal = (Set) value;
149 Set newContent = new ManagedSet();
150 boolean entriesModified = false;
151 for (Iterator it = setVal.iterator(); it.hasNext();) {
152 Object elem = it.next();
153 int elemHash = (elem != null ? elem.hashCode() : 0);
154 Object newVal = resolveValue(beanName, bean, elem);
155 int newValHash = (newVal != null ? newVal.hashCode() : 0);
156 newContent.add(newVal);
157 entriesModified = entriesModified
158 || (newVal != elem || newValHash != elemHash);
159 }
160 return entriesModified ? newContent : value;
161 } else {
162 //log.debug(beanName + ": " + value.getClass() + " : " + value);
163 return value;
164 }
165
166 }
167
168 private String resolveString(String beanName, Object bean, String strVal) {
169 String value = parseStringValue(bean, strVal, new HashSet<String>());
170
171 if (value == null)
172 throw new SlcException("Could not resolve placeholder '" + strVal
173 + "' in bean '" + beanName + "'");
174
175 return (value.equals(nullValue) ? null : value);
176 }
177
178 public void setPlaceholderPrefix(String placeholderPrefix) {
179 this.placeholderPrefix = placeholderPrefix;
180 }
181
182 public void setPlaceholderSuffix(String placeholderSuffix) {
183 this.placeholderSuffix = placeholderSuffix;
184 }
185
186 public void setNullValue(String nullValue) {
187 this.nullValue = nullValue;
188 }
189
190 public void setInstantiationManager(
191 InstantiationManager instantiationManager) {
192 this.instantiationManager = instantiationManager;
193 }
194
195 public void setExecutionContext(ExecutionContext executionContext) {
196 this.executionContext = executionContext;
197 }
198
199 //
200 // Following methods hacked from the internals of
201 // PropertyPlaceholderConfigurer
202 //
203
204 protected String parseStringValue(Object bean, String strVal,
205 Set<String> visitedPlaceholders)
206 throws BeanDefinitionStoreException {
207
208 StringBuffer buf = new StringBuffer(strVal);
209
210 int startIndex = strVal.indexOf(placeholderPrefix);
211 while (startIndex != -1) {
212 int endIndex = findPlaceholderEndIndex(buf, startIndex);
213 if (endIndex != -1) {
214 String placeholder = buf.substring(startIndex
215 + placeholderPrefix.length(), endIndex);
216 if (!visitedPlaceholders.add(placeholder)) {
217 throw new BeanDefinitionStoreException(
218 "Circular placeholder reference '" + placeholder
219 + "' in property definitions");
220 }
221 // Recursive invocation, parsing placeholders contained in
222 // the placeholder key.
223 placeholder = parseStringValue(bean, placeholder,
224 visitedPlaceholders);
225 // Now obtain the value for the fully resolved key...
226 String propVal = resolvePlaceholder(bean, placeholder);
227 if (propVal != null) {
228 // Recursive invocation, parsing placeholders contained
229 // in the
230 // previously resolved placeholder value.
231 propVal = parseStringValue(bean, propVal,
232 visitedPlaceholders);
233 buf.replace(startIndex, endIndex
234 + placeholderSuffix.length(), propVal);
235 if (log.isTraceEnabled()) {
236 log.trace("Resolved placeholder '" + placeholder + "'");
237 }
238 startIndex = buf.indexOf(placeholderPrefix, startIndex
239 + propVal.length());
240 } else {
241 throw new BeanDefinitionStoreException(
242 "Could not resolve placeholder '" + placeholder
243 + "'");
244 }
245 visitedPlaceholders.remove(placeholder);
246 } else {
247 startIndex = -1;
248 }
249 }
250
251 return buf.toString();
252 }
253
254 private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
255 int index = startIndex + placeholderPrefix.length();
256 int withinNestedPlaceholder = 0;
257 while (index < buf.length()) {
258 if (StringUtils.substringMatch(buf, index, placeholderSuffix)) {
259 if (withinNestedPlaceholder > 0) {
260 withinNestedPlaceholder--;
261 index = index + placeholderSuffix.length();
262 } else {
263 return index;
264 }
265 } else if (StringUtils
266 .substringMatch(buf, index, placeholderPrefix)) {
267 withinNestedPlaceholder++;
268 index = index + placeholderPrefix.length();
269 } else {
270 index++;
271 }
272 }
273 return -1;
274 }
275
276 }