1 package org
.argeo
.slc
.core
.execution
;
3 import java
.beans
.PropertyDescriptor
;
4 import java
.util
.HashSet
;
5 import java
.util
.Iterator
;
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
.argeo
.slc
.runtime
.InstantiationManager
;
16 import org
.springframework
.beans
.BeansException
;
17 import org
.springframework
.beans
.MutablePropertyValues
;
18 import org
.springframework
.beans
.PropertyValue
;
19 import org
.springframework
.beans
.PropertyValues
;
20 import org
.springframework
.beans
.factory
.BeanDefinitionStoreException
;
21 import org
.springframework
.beans
.factory
.config
.InstantiationAwareBeanPostProcessorAdapter
;
22 import org
.springframework
.beans
.factory
.config
.TypedStringValue
;
23 import org
.springframework
.beans
.factory
.support
.ManagedList
;
24 import org
.springframework
.beans
.factory
.support
.ManagedMap
;
25 import org
.springframework
.beans
.factory
.support
.ManagedSet
;
26 import org
.springframework
.util
.ObjectUtils
;
27 import org
.springframework
.util
.StringUtils
;
30 * Spring post processor which ensures that execution parameters are properly
31 * set. It is used at two levels: first during instantiation for instantiation
32 * parameters which allow to implement templates, then at runtime in order to
33 * interpret @{} placeholders when object of scope execution are instantiated.
35 public class ExecutionParameterPostProcessor
extends
36 InstantiationAwareBeanPostProcessorAdapter
{
38 private final static Log log
= LogFactory
39 .getLog(ExecutionParameterPostProcessor
.class);
41 private ExecutionContext executionContext
;
42 private InstantiationManager instantiationManager
;
44 private String placeholderPrefix
= "@{";
45 private String placeholderSuffix
= "}";
46 private String nullValue
;
49 public PropertyValues
postProcessPropertyValues(PropertyValues pvs
,
50 PropertyDescriptor
[] pds
, Object bean
, String beanName
)
51 throws BeansException
{
53 // TODO: resolve at execution only if scope is execution
54 // TODO: deal with placeholders in RuntimeBeanReference and
55 // RuntimeBeanNameReference
57 MutablePropertyValues newPvs
= new MutablePropertyValues();
59 boolean changesOccured
= false;
61 for (PropertyValue pv
: pvs
.getPropertyValues()) {
62 Object convertedValue
= resolveValue(beanName
, bean
, pv
.getValue());
63 newPvs
.addPropertyValue(new PropertyValue(pv
, convertedValue
));
64 if (convertedValue
!= pv
.getValue()) {
65 changesOccured
= true;
69 return changesOccured ? newPvs
: pvs
;
73 public boolean postProcessAfterInstantiation(Object bean
, String beanName
)
74 throws BeansException
{
75 if (bean
instanceof ExecutionFlow
)
76 instantiationManager
.flowInitializationStarted(
77 (ExecutionFlow
) bean
, beanName
);
82 public Object
postProcessAfterInitialization(Object bean
, String beanName
)
83 throws BeansException
{
84 if (bean
instanceof ExecutionFlow
)
85 instantiationManager
.flowInitializationFinished(
86 (ExecutionFlow
) bean
, beanName
);
90 protected String
resolvePlaceholder(Object bean
, String placeholder
) {
91 if (instantiationManager
.isInFlowInitialization())
92 return instantiationManager
.getInitializingFlowParameter(
93 placeholder
).toString();
96 // next call fail if no execution context available
97 Object obj
= executionContext
.getVariable(placeholder
);
99 return obj
.toString();
106 public Object
resolveValue(String beanName
, Object bean
, Object value
) {
107 if (value
instanceof TypedStringValue
) {
108 TypedStringValue tsv
= (TypedStringValue
) value
;
109 String originalValue
= tsv
.getValue();
111 String convertedValue
= resolveString(beanName
, bean
, originalValue
);
112 if (convertedValue
== null)
114 return convertedValue
.equals(originalValue
) ? value
115 : new TypedStringValue(convertedValue
);
116 } else if (value
instanceof String
) {
117 String originalValue
= value
.toString();
118 String convertedValue
= resolveString(beanName
, bean
, originalValue
);
119 if (convertedValue
== null)
121 return convertedValue
.equals(originalValue
) ? value
123 } else if (value
instanceof ManagedMap
) {
124 Map
<?
, ?
> mapVal
= (Map
<?
, ?
>) value
;
126 Map
<Object
, Object
> newContent
= new ManagedMap
<Object
, Object
>();
127 boolean entriesModified
= false;
128 for (Iterator
<?
> it
= mapVal
.entrySet().iterator(); it
.hasNext();) {
129 Map
.Entry
<?
, ?
> entry
= (Map
.Entry
<?
, ?
>) it
.next();
130 Object key
= entry
.getKey();
131 int keyHash
= (key
!= null ? key
.hashCode() : 0);
132 Object newKey
= resolveValue(beanName
, bean
, key
);
133 int newKeyHash
= (newKey
!= null ? newKey
.hashCode() : 0);
134 Object val
= entry
.getValue();
135 Object newVal
= resolveValue(beanName
, bean
, val
);
136 newContent
.put(newKey
, newVal
);
137 entriesModified
= entriesModified
138 || (newVal
!= val
|| newKey
!= key
|| newKeyHash
!= keyHash
);
141 return entriesModified ? newContent
: value
;
142 } else if (value
instanceof ManagedList
) {
143 List
<?
> listVal
= (List
<?
>) value
;
144 List
<Object
> newContent
= new ManagedList
<Object
>();
145 boolean valueModified
= false;
147 for (int i
= 0; i
< listVal
.size(); i
++) {
148 Object elem
= listVal
.get(i
);
149 Object newVal
= resolveValue(beanName
, bean
, elem
);
150 newContent
.add(newVal
);
151 if (!ObjectUtils
.nullSafeEquals(newVal
, elem
)) {
152 valueModified
= true;
155 return valueModified ? newContent
: value
;
156 } else if (value
instanceof ManagedSet
) {
157 Set
<?
> setVal
= (Set
<?
>) value
;
158 Set
<Object
> newContent
= new ManagedSet
<Object
>();
159 boolean entriesModified
= false;
160 for (Iterator
<?
> it
= setVal
.iterator(); it
.hasNext();) {
161 Object elem
= it
.next();
162 int elemHash
= (elem
!= null ? elem
.hashCode() : 0);
163 Object newVal
= resolveValue(beanName
, bean
, elem
);
164 int newValHash
= (newVal
!= null ? newVal
.hashCode() : 0);
165 newContent
.add(newVal
);
166 entriesModified
= entriesModified
167 || (newVal
!= elem
|| newValHash
!= elemHash
);
169 return entriesModified ? newContent
: value
;
171 // log.debug(beanName + ": " + value.getClass() + " : " + value);
177 private String
resolveString(String beanName
, Object bean
, String strVal
) {
178 // in case <null/> is passed
182 String value
= parseStringValue(bean
, strVal
, new HashSet
<String
>());
185 throw new SlcException("Could not resolve placeholder '" + strVal
186 + "' in bean '" + beanName
+ "'");
188 return (value
.equals(nullValue
) ?
null : value
);
191 public void setPlaceholderPrefix(String placeholderPrefix
) {
192 this.placeholderPrefix
= placeholderPrefix
;
195 public void setPlaceholderSuffix(String placeholderSuffix
) {
196 this.placeholderSuffix
= placeholderSuffix
;
199 public void setNullValue(String nullValue
) {
200 this.nullValue
= nullValue
;
203 public void setInstantiationManager(
204 InstantiationManager instantiationManager
) {
205 this.instantiationManager
= instantiationManager
;
208 public void setExecutionContext(ExecutionContext executionContext
) {
209 this.executionContext
= executionContext
;
213 // Following methods hacked from the internals of
214 // PropertyPlaceholderConfigurer
217 protected String
parseStringValue(Object bean
, String strVal
,
218 Set
<String
> visitedPlaceholders
)
219 throws BeanDefinitionStoreException
{
221 // in case <null/> is passed
225 StringBuffer buf
= new StringBuffer(strVal
);
227 int startIndex
= strVal
.indexOf(placeholderPrefix
);
228 while (startIndex
!= -1) {
229 int endIndex
= findPlaceholderEndIndex(buf
, startIndex
);
230 if (endIndex
!= -1) {
231 String placeholder
= buf
.substring(startIndex
232 + placeholderPrefix
.length(), endIndex
);
233 if (!visitedPlaceholders
.add(placeholder
)) {
234 throw new BeanDefinitionStoreException(
235 "Circular placeholder reference '" + placeholder
236 + "' in property definitions");
238 // Recursive invocation, parsing placeholders contained in
239 // the placeholder key.
240 placeholder
= parseStringValue(bean
, placeholder
,
241 visitedPlaceholders
);
242 // Now obtain the value for the fully resolved key...
243 String propVal
= resolvePlaceholder(bean
, placeholder
);
244 if (propVal
!= null) {
245 // Recursive invocation, parsing placeholders contained
247 // previously resolved placeholder value.
248 propVal
= parseStringValue(bean
, propVal
,
249 visitedPlaceholders
);
250 buf
.replace(startIndex
,
251 endIndex
+ placeholderSuffix
.length(), propVal
);
252 if (log
.isTraceEnabled()) {
253 log
.trace("Resolved placeholder '" + placeholder
+ "'");
255 startIndex
= buf
.indexOf(placeholderPrefix
, startIndex
258 throw new BeanDefinitionStoreException(
259 "Could not resolve placeholder '" + placeholder
262 visitedPlaceholders
.remove(placeholder
);
268 return buf
.toString();
271 private int findPlaceholderEndIndex(CharSequence buf
, int startIndex
) {
272 int index
= startIndex
+ placeholderPrefix
.length();
273 int withinNestedPlaceholder
= 0;
274 while (index
< buf
.length()) {
275 if (StringUtils
.substringMatch(buf
, index
, placeholderSuffix
)) {
276 if (withinNestedPlaceholder
> 0) {
277 withinNestedPlaceholder
--;
278 index
= index
+ placeholderSuffix
.length();
282 } else if (StringUtils
283 .substringMatch(buf
, index
, placeholderPrefix
)) {
284 withinNestedPlaceholder
++;
285 index
= index
+ placeholderPrefix
.length();