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