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
.argeo
.api
.cms
.CmsLog
;
11 import org
.argeo
.slc
.SlcException
;
12 import org
.argeo
.slc
.execution
.ExecutionContext
;
13 import org
.argeo
.slc
.execution
.ExecutionFlow
;
14 import org
.argeo
.slc
.runtime
.InstantiationManager
;
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
;
29 * Spring post processor which ensures that execution parameters are properly
30 * set. It is used at two levels: first during instantiation for instantiation
31 * parameters which allow to implement templates, then at runtime in order to
32 * interpret @{} placeholders when object of scope execution are instantiated.
34 public class ExecutionParameterPostProcessor
extends
35 InstantiationAwareBeanPostProcessorAdapter
{
37 private final static CmsLog log
= CmsLog
38 .getLog(ExecutionParameterPostProcessor
.class);
40 private ExecutionContext executionContext
;
41 private InstantiationManager instantiationManager
;
43 private String placeholderPrefix
= "@{";
44 private String placeholderSuffix
= "}";
45 private String nullValue
;
48 public PropertyValues
postProcessPropertyValues(PropertyValues pvs
,
49 PropertyDescriptor
[] pds
, Object bean
, String beanName
)
50 throws BeansException
{
52 // TODO: resolve at execution only if scope is execution
53 // TODO: deal with placeholders in RuntimeBeanReference and
54 // RuntimeBeanNameReference
56 MutablePropertyValues newPvs
= new MutablePropertyValues();
58 boolean changesOccured
= false;
60 for (PropertyValue pv
: pvs
.getPropertyValues()) {
61 Object convertedValue
= resolveValue(beanName
, bean
, pv
.getValue());
62 newPvs
.addPropertyValue(new PropertyValue(pv
, convertedValue
));
63 if (convertedValue
!= pv
.getValue()) {
64 changesOccured
= true;
68 return changesOccured ? newPvs
: pvs
;
72 public boolean postProcessAfterInstantiation(Object bean
, String beanName
)
73 throws BeansException
{
74 if (bean
instanceof ExecutionFlow
)
75 instantiationManager
.flowInitializationStarted(
76 (ExecutionFlow
) bean
, beanName
);
81 public Object
postProcessAfterInitialization(Object bean
, String beanName
)
82 throws BeansException
{
83 if (bean
instanceof ExecutionFlow
)
84 instantiationManager
.flowInitializationFinished(
85 (ExecutionFlow
) bean
, beanName
);
89 protected String
resolvePlaceholder(Object bean
, String placeholder
) {
90 if (instantiationManager
.isInFlowInitialization())
91 return instantiationManager
.getInitializingFlowParameter(
92 placeholder
).toString();
95 // next call fail if no execution context available
96 Object obj
= executionContext
.getVariable(placeholder
);
98 return obj
.toString();
105 public Object
resolveValue(String beanName
, Object bean
, Object value
) {
106 if (value
instanceof TypedStringValue
) {
107 TypedStringValue tsv
= (TypedStringValue
) value
;
108 String originalValue
= tsv
.getValue();
110 String convertedValue
= resolveString(beanName
, bean
, originalValue
);
111 if (convertedValue
== null)
113 return convertedValue
.equals(originalValue
) ? value
114 : new TypedStringValue(convertedValue
);
115 } else if (value
instanceof String
) {
116 String originalValue
= value
.toString();
117 String convertedValue
= resolveString(beanName
, bean
, originalValue
);
118 if (convertedValue
== null)
120 return convertedValue
.equals(originalValue
) ? value
122 } else if (value
instanceof ManagedMap
) {
123 Map
<?
, ?
> mapVal
= (Map
<?
, ?
>) value
;
125 Map
<Object
, Object
> newContent
= new ManagedMap
<Object
, Object
>();
126 boolean entriesModified
= false;
127 for (Iterator
<?
> it
= mapVal
.entrySet().iterator(); it
.hasNext();) {
128 Map
.Entry
<?
, ?
> entry
= (Map
.Entry
<?
, ?
>) it
.next();
129 Object key
= entry
.getKey();
130 int keyHash
= (key
!= null ? key
.hashCode() : 0);
131 Object newKey
= resolveValue(beanName
, bean
, key
);
132 int newKeyHash
= (newKey
!= null ? newKey
.hashCode() : 0);
133 Object val
= entry
.getValue();
134 Object newVal
= resolveValue(beanName
, bean
, val
);
135 newContent
.put(newKey
, newVal
);
136 entriesModified
= entriesModified
137 || (newVal
!= val
|| newKey
!= key
|| newKeyHash
!= keyHash
);
140 return entriesModified ? newContent
: value
;
141 } else if (value
instanceof ManagedList
) {
142 List
<?
> listVal
= (List
<?
>) value
;
143 List
<Object
> newContent
= new ManagedList
<Object
>();
144 boolean valueModified
= false;
146 for (int i
= 0; i
< listVal
.size(); i
++) {
147 Object elem
= listVal
.get(i
);
148 Object newVal
= resolveValue(beanName
, bean
, elem
);
149 newContent
.add(newVal
);
150 if (!ObjectUtils
.nullSafeEquals(newVal
, elem
)) {
151 valueModified
= true;
154 return valueModified ? newContent
: value
;
155 } else if (value
instanceof ManagedSet
) {
156 Set
<?
> setVal
= (Set
<?
>) value
;
157 Set
<Object
> newContent
= new ManagedSet
<Object
>();
158 boolean entriesModified
= false;
159 for (Iterator
<?
> it
= setVal
.iterator(); it
.hasNext();) {
160 Object elem
= it
.next();
161 int elemHash
= (elem
!= null ? elem
.hashCode() : 0);
162 Object newVal
= resolveValue(beanName
, bean
, elem
);
163 int newValHash
= (newVal
!= null ? newVal
.hashCode() : 0);
164 newContent
.add(newVal
);
165 entriesModified
= entriesModified
166 || (newVal
!= elem
|| newValHash
!= elemHash
);
168 return entriesModified ? newContent
: value
;
170 // log.debug(beanName + ": " + value.getClass() + " : " + value);
176 private String
resolveString(String beanName
, Object bean
, String strVal
) {
177 // in case <null/> is passed
181 String value
= parseStringValue(bean
, strVal
, new HashSet
<String
>());
184 throw new SlcException("Could not resolve placeholder '" + strVal
185 + "' in bean '" + beanName
+ "'");
187 return (value
.equals(nullValue
) ?
null : value
);
190 public void setPlaceholderPrefix(String placeholderPrefix
) {
191 this.placeholderPrefix
= placeholderPrefix
;
194 public void setPlaceholderSuffix(String placeholderSuffix
) {
195 this.placeholderSuffix
= placeholderSuffix
;
198 public void setNullValue(String nullValue
) {
199 this.nullValue
= nullValue
;
202 public void setInstantiationManager(
203 InstantiationManager instantiationManager
) {
204 this.instantiationManager
= instantiationManager
;
207 public void setExecutionContext(ExecutionContext executionContext
) {
208 this.executionContext
= executionContext
;
212 // Following methods hacked from the internals of
213 // PropertyPlaceholderConfigurer
216 protected String
parseStringValue(Object bean
, String strVal
,
217 Set
<String
> visitedPlaceholders
)
218 throws BeanDefinitionStoreException
{
220 // in case <null/> is passed
224 StringBuffer buf
= new StringBuffer(strVal
);
226 int startIndex
= strVal
.indexOf(placeholderPrefix
);
227 while (startIndex
!= -1) {
228 int endIndex
= findPlaceholderEndIndex(buf
, startIndex
);
229 if (endIndex
!= -1) {
230 String placeholder
= buf
.substring(startIndex
231 + placeholderPrefix
.length(), endIndex
);
232 if (!visitedPlaceholders
.add(placeholder
)) {
233 throw new BeanDefinitionStoreException(
234 "Circular placeholder reference '" + placeholder
235 + "' in property definitions");
237 // Recursive invocation, parsing placeholders contained in
238 // the placeholder key.
239 placeholder
= parseStringValue(bean
, placeholder
,
240 visitedPlaceholders
);
241 // Now obtain the value for the fully resolved key...
242 String propVal
= resolvePlaceholder(bean
, placeholder
);
243 if (propVal
!= null) {
244 // Recursive invocation, parsing placeholders contained
246 // previously resolved placeholder value.
247 propVal
= parseStringValue(bean
, propVal
,
248 visitedPlaceholders
);
249 buf
.replace(startIndex
,
250 endIndex
+ placeholderSuffix
.length(), propVal
);
251 if (log
.isTraceEnabled()) {
252 log
.trace("Resolved placeholder '" + placeholder
+ "'");
254 startIndex
= buf
.indexOf(placeholderPrefix
, startIndex
257 throw new BeanDefinitionStoreException(
258 "Could not resolve placeholder '" + placeholder
261 visitedPlaceholders
.remove(placeholder
);
267 return buf
.toString();
270 private int findPlaceholderEndIndex(CharSequence buf
, int startIndex
) {
271 int index
= startIndex
+ placeholderPrefix
.length();
272 int withinNestedPlaceholder
= 0;
273 while (index
< buf
.length()) {
274 if (StringUtils
.substringMatch(buf
, index
, placeholderSuffix
)) {
275 if (withinNestedPlaceholder
> 0) {
276 withinNestedPlaceholder
--;
277 index
= index
+ placeholderSuffix
.length();
281 } else if (StringUtils
282 .substringMatch(buf
, index
, placeholderPrefix
)) {
283 withinNestedPlaceholder
++;
284 index
= index
+ placeholderPrefix
.length();