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