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