-/*\r
- * Copyright (C) 2007-2012 Argeo GmbH\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.argeo.slc.core.execution;\r
-\r
-import java.beans.PropertyDescriptor;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-\r
-import org.apache.commons.logging.Log;\r
-import org.apache.commons.logging.LogFactory;\r
-import org.argeo.slc.SlcException;\r
-import org.argeo.slc.execution.ExecutionContext;\r
-import org.argeo.slc.execution.ExecutionFlow;\r
-import org.argeo.slc.runtime.InstantiationManager;\r
-import org.springframework.beans.BeansException;\r
-import org.springframework.beans.MutablePropertyValues;\r
-import org.springframework.beans.PropertyValue;\r
-import org.springframework.beans.PropertyValues;\r
-import org.springframework.beans.factory.BeanDefinitionStoreException;\r
-import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;\r
-import org.springframework.beans.factory.config.TypedStringValue;\r
-import org.springframework.beans.factory.support.ManagedList;\r
-import org.springframework.beans.factory.support.ManagedMap;\r
-import org.springframework.beans.factory.support.ManagedSet;\r
-import org.springframework.util.ObjectUtils;\r
-import org.springframework.util.StringUtils;\r
-\r
-/**\r
- * Spring post processor which ensures that execution parameters are properly\r
- * set. It is used at two levels: first during instantiation for instantiation\r
- * parameters which allow to implement templates, then at runtime in order to\r
- * interpret @{} placeholders when object of scope execution are instantiated.\r
- */\r
-public class ExecutionParameterPostProcessor extends\r
- InstantiationAwareBeanPostProcessorAdapter {\r
-\r
- private final static Log log = LogFactory\r
- .getLog(ExecutionParameterPostProcessor.class);\r
-\r
- private ExecutionContext executionContext;\r
- private InstantiationManager instantiationManager;\r
-\r
- private String placeholderPrefix = "@{";\r
- private String placeholderSuffix = "}";\r
- private String nullValue;\r
-\r
- @Override\r
- public PropertyValues postProcessPropertyValues(PropertyValues pvs,\r
- PropertyDescriptor[] pds, Object bean, String beanName)\r
- throws BeansException {\r
-\r
- // TODO: resolve at execution only if scope is execution\r
- // TODO: deal with placeholders in RuntimeBeanReference and\r
- // RuntimeBeanNameReference\r
-\r
- MutablePropertyValues newPvs = new MutablePropertyValues();\r
-\r
- boolean changesOccured = false;\r
-\r
- for (PropertyValue pv : pvs.getPropertyValues()) {\r
- Object convertedValue = resolveValue(beanName, bean, pv.getValue());\r
- newPvs.addPropertyValue(new PropertyValue(pv, convertedValue));\r
- if (convertedValue != pv.getValue()) {\r
- changesOccured = true;\r
- }\r
- }\r
-\r
- return changesOccured ? newPvs : pvs;\r
- }\r
-\r
- @Override\r
- public boolean postProcessAfterInstantiation(Object bean, String beanName)\r
- throws BeansException {\r
- if (bean instanceof ExecutionFlow)\r
- instantiationManager.flowInitializationStarted(\r
- (ExecutionFlow) bean, beanName);\r
- return true;\r
- }\r
-\r
- @Override\r
- public Object postProcessAfterInitialization(Object bean, String beanName)\r
- throws BeansException {\r
- if (bean instanceof ExecutionFlow)\r
- instantiationManager.flowInitializationFinished(\r
- (ExecutionFlow) bean, beanName);\r
- return bean;\r
- }\r
-\r
- protected String resolvePlaceholder(Object bean, String placeholder) {\r
- if (instantiationManager.isInFlowInitialization())\r
- return instantiationManager.getInitializingFlowParameter(\r
- placeholder).toString();\r
-\r
- else {// execution\r
- // next call fail if no execution context available\r
- Object obj = executionContext.getVariable(placeholder);\r
- if (obj != null) {\r
- return obj.toString();\r
- }\r
- }\r
-\r
- return null;\r
- }\r
-\r
- public Object resolveValue(String beanName, Object bean, Object value) {\r
- if (value instanceof TypedStringValue) {\r
- TypedStringValue tsv = (TypedStringValue) value;\r
- String originalValue = tsv.getValue();\r
-\r
- String convertedValue = resolveString(beanName, bean, originalValue);\r
- if (convertedValue == null)\r
- return null;\r
- return convertedValue.equals(originalValue) ? value\r
- : new TypedStringValue(convertedValue);\r
- } else if (value instanceof String) {\r
- String originalValue = value.toString();\r
- String convertedValue = resolveString(beanName, bean, originalValue);\r
- if (convertedValue == null)\r
- return null;\r
- return convertedValue.equals(originalValue) ? value\r
- : convertedValue;\r
- } else if (value instanceof ManagedMap) {\r
- Map<?, ?> mapVal = (Map<?, ?>) value;\r
-\r
- Map<Object, Object> newContent = new ManagedMap<Object, Object>();\r
- boolean entriesModified = false;\r
- for (Iterator<?> it = mapVal.entrySet().iterator(); it.hasNext();) {\r
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();\r
- Object key = entry.getKey();\r
- int keyHash = (key != null ? key.hashCode() : 0);\r
- Object newKey = resolveValue(beanName, bean, key);\r
- int newKeyHash = (newKey != null ? newKey.hashCode() : 0);\r
- Object val = entry.getValue();\r
- Object newVal = resolveValue(beanName, bean, val);\r
- newContent.put(newKey, newVal);\r
- entriesModified = entriesModified\r
- || (newVal != val || newKey != key || newKeyHash != keyHash);\r
- }\r
-\r
- return entriesModified ? newContent : value;\r
- } else if (value instanceof ManagedList) {\r
- List<?> listVal = (List<?>) value;\r
- List<Object> newContent = new ManagedList<Object>();\r
- boolean valueModified = false;\r
-\r
- for (int i = 0; i < listVal.size(); i++) {\r
- Object elem = listVal.get(i);\r
- Object newVal = resolveValue(beanName, bean, elem);\r
- newContent.add(newVal);\r
- if (!ObjectUtils.nullSafeEquals(newVal, elem)) {\r
- valueModified = true;\r
- }\r
- }\r
- return valueModified ? newContent : value;\r
- } else if (value instanceof ManagedSet) {\r
- Set<?> setVal = (Set<?>) value;\r
- Set<Object> newContent = new ManagedSet<Object>();\r
- boolean entriesModified = false;\r
- for (Iterator<?> it = setVal.iterator(); it.hasNext();) {\r
- Object elem = it.next();\r
- int elemHash = (elem != null ? elem.hashCode() : 0);\r
- Object newVal = resolveValue(beanName, bean, elem);\r
- int newValHash = (newVal != null ? newVal.hashCode() : 0);\r
- newContent.add(newVal);\r
- entriesModified = entriesModified\r
- || (newVal != elem || newValHash != elemHash);\r
- }\r
- return entriesModified ? newContent : value;\r
- } else {\r
- // log.debug(beanName + ": " + value.getClass() + " : " + value);\r
- return value;\r
- }\r
-\r
- }\r
-\r
- private String resolveString(String beanName, Object bean, String strVal) {\r
- // in case <null/> is passed\r
- if (strVal == null)\r
- return null;\r
-\r
- String value = parseStringValue(bean, strVal, new HashSet<String>());\r
-\r
- if (value == null)\r
- throw new SlcException("Could not resolve placeholder '" + strVal\r
- + "' in bean '" + beanName + "'");\r
-\r
- return (value.equals(nullValue) ? null : value);\r
- }\r
-\r
- public void setPlaceholderPrefix(String placeholderPrefix) {\r
- this.placeholderPrefix = placeholderPrefix;\r
- }\r
-\r
- public void setPlaceholderSuffix(String placeholderSuffix) {\r
- this.placeholderSuffix = placeholderSuffix;\r
- }\r
-\r
- public void setNullValue(String nullValue) {\r
- this.nullValue = nullValue;\r
- }\r
-\r
- public void setInstantiationManager(\r
- InstantiationManager instantiationManager) {\r
- this.instantiationManager = instantiationManager;\r
- }\r
-\r
- public void setExecutionContext(ExecutionContext executionContext) {\r
- this.executionContext = executionContext;\r
- }\r
-\r
- //\r
- // Following methods hacked from the internals of\r
- // PropertyPlaceholderConfigurer\r
- //\r
-\r
- protected String parseStringValue(Object bean, String strVal,\r
- Set<String> visitedPlaceholders)\r
- throws BeanDefinitionStoreException {\r
-\r
- // in case <null/> is passed\r
- if (strVal == null)\r
- return null;\r
-\r
- StringBuffer buf = new StringBuffer(strVal);\r
-\r
- int startIndex = strVal.indexOf(placeholderPrefix);\r
- while (startIndex != -1) {\r
- int endIndex = findPlaceholderEndIndex(buf, startIndex);\r
- if (endIndex != -1) {\r
- String placeholder = buf.substring(startIndex\r
- + placeholderPrefix.length(), endIndex);\r
- if (!visitedPlaceholders.add(placeholder)) {\r
- throw new BeanDefinitionStoreException(\r
- "Circular placeholder reference '" + placeholder\r
- + "' in property definitions");\r
- }\r
- // Recursive invocation, parsing placeholders contained in\r
- // the placeholder key.\r
- placeholder = parseStringValue(bean, placeholder,\r
- visitedPlaceholders);\r
- // Now obtain the value for the fully resolved key...\r
- String propVal = resolvePlaceholder(bean, placeholder);\r
- if (propVal != null) {\r
- // Recursive invocation, parsing placeholders contained\r
- // in the\r
- // previously resolved placeholder value.\r
- propVal = parseStringValue(bean, propVal,\r
- visitedPlaceholders);\r
- buf.replace(startIndex,\r
- endIndex + placeholderSuffix.length(), propVal);\r
- if (log.isTraceEnabled()) {\r
- log.trace("Resolved placeholder '" + placeholder + "'");\r
- }\r
- startIndex = buf.indexOf(placeholderPrefix, startIndex\r
- + propVal.length());\r
- } else {\r
- throw new BeanDefinitionStoreException(\r
- "Could not resolve placeholder '" + placeholder\r
- + "'");\r
- }\r
- visitedPlaceholders.remove(placeholder);\r
- } else {\r
- startIndex = -1;\r
- }\r
- }\r
-\r
- return buf.toString();\r
- }\r
-\r
- private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {\r
- int index = startIndex + placeholderPrefix.length();\r
- int withinNestedPlaceholder = 0;\r
- while (index < buf.length()) {\r
- if (StringUtils.substringMatch(buf, index, placeholderSuffix)) {\r
- if (withinNestedPlaceholder > 0) {\r
- withinNestedPlaceholder--;\r
- index = index + placeholderSuffix.length();\r
- } else {\r
- return index;\r
- }\r
- } else if (StringUtils\r
- .substringMatch(buf, index, placeholderPrefix)) {\r
- withinNestedPlaceholder++;\r
- index = index + placeholderPrefix.length();\r
- } else {\r
- index++;\r
- }\r
- }\r
- return -1;\r
- }\r
-\r
-}\r
+package org.argeo.slc.core.execution;
+
+import java.beans.PropertyDescriptor;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.execution.ExecutionContext;
+import org.argeo.slc.execution.ExecutionFlow;
+import org.argeo.slc.runtime.InstantiationManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
+import org.springframework.beans.factory.config.TypedStringValue;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.support.ManagedSet;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * Spring post processor which ensures that execution parameters are properly
+ * set. It is used at two levels: first during instantiation for instantiation
+ * parameters which allow to implement templates, then at runtime in order to
+ * interpret @{} placeholders when object of scope execution are instantiated.
+ */
+public class ExecutionParameterPostProcessor extends
+ InstantiationAwareBeanPostProcessorAdapter {
+
+ private final static Log log = LogFactory
+ .getLog(ExecutionParameterPostProcessor.class);
+
+ private ExecutionContext executionContext;
+ private InstantiationManager instantiationManager;
+
+ private String placeholderPrefix = "@{";
+ private String placeholderSuffix = "}";
+ private String nullValue;
+
+ @Override
+ public PropertyValues postProcessPropertyValues(PropertyValues pvs,
+ PropertyDescriptor[] pds, Object bean, String beanName)
+ throws BeansException {
+
+ // TODO: resolve at execution only if scope is execution
+ // TODO: deal with placeholders in RuntimeBeanReference and
+ // RuntimeBeanNameReference
+
+ MutablePropertyValues newPvs = new MutablePropertyValues();
+
+ boolean changesOccured = false;
+
+ for (PropertyValue pv : pvs.getPropertyValues()) {
+ Object convertedValue = resolveValue(beanName, bean, pv.getValue());
+ newPvs.addPropertyValue(new PropertyValue(pv, convertedValue));
+ if (convertedValue != pv.getValue()) {
+ changesOccured = true;
+ }
+ }
+
+ return changesOccured ? newPvs : pvs;
+ }
+
+ @Override
+ public boolean postProcessAfterInstantiation(Object bean, String beanName)
+ throws BeansException {
+ if (bean instanceof ExecutionFlow)
+ instantiationManager.flowInitializationStarted(
+ (ExecutionFlow) bean, beanName);
+ return true;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ if (bean instanceof ExecutionFlow)
+ instantiationManager.flowInitializationFinished(
+ (ExecutionFlow) bean, beanName);
+ return bean;
+ }
+
+ protected String resolvePlaceholder(Object bean, String placeholder) {
+ if (instantiationManager.isInFlowInitialization())
+ return instantiationManager.getInitializingFlowParameter(
+ placeholder).toString();
+
+ else {// execution
+ // next call fail if no execution context available
+ Object obj = executionContext.getVariable(placeholder);
+ if (obj != null) {
+ return obj.toString();
+ }
+ }
+
+ return null;
+ }
+
+ public Object resolveValue(String beanName, Object bean, Object value) {
+ if (value instanceof TypedStringValue) {
+ TypedStringValue tsv = (TypedStringValue) value;
+ String originalValue = tsv.getValue();
+
+ String convertedValue = resolveString(beanName, bean, originalValue);
+ if (convertedValue == null)
+ return null;
+ return convertedValue.equals(originalValue) ? value
+ : new TypedStringValue(convertedValue);
+ } else if (value instanceof String) {
+ String originalValue = value.toString();
+ String convertedValue = resolveString(beanName, bean, originalValue);
+ if (convertedValue == null)
+ return null;
+ return convertedValue.equals(originalValue) ? value
+ : convertedValue;
+ } else if (value instanceof ManagedMap) {
+ Map<?, ?> mapVal = (Map<?, ?>) value;
+
+ Map<Object, Object> newContent = new ManagedMap<Object, Object>();
+ boolean entriesModified = false;
+ for (Iterator<?> it = mapVal.entrySet().iterator(); it.hasNext();) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
+ Object key = entry.getKey();
+ int keyHash = (key != null ? key.hashCode() : 0);
+ Object newKey = resolveValue(beanName, bean, key);
+ int newKeyHash = (newKey != null ? newKey.hashCode() : 0);
+ Object val = entry.getValue();
+ Object newVal = resolveValue(beanName, bean, val);
+ newContent.put(newKey, newVal);
+ entriesModified = entriesModified
+ || (newVal != val || newKey != key || newKeyHash != keyHash);
+ }
+
+ return entriesModified ? newContent : value;
+ } else if (value instanceof ManagedList) {
+ List<?> listVal = (List<?>) value;
+ List<Object> newContent = new ManagedList<Object>();
+ boolean valueModified = false;
+
+ for (int i = 0; i < listVal.size(); i++) {
+ Object elem = listVal.get(i);
+ Object newVal = resolveValue(beanName, bean, elem);
+ newContent.add(newVal);
+ if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
+ valueModified = true;
+ }
+ }
+ return valueModified ? newContent : value;
+ } else if (value instanceof ManagedSet) {
+ Set<?> setVal = (Set<?>) value;
+ Set<Object> newContent = new ManagedSet<Object>();
+ boolean entriesModified = false;
+ for (Iterator<?> it = setVal.iterator(); it.hasNext();) {
+ Object elem = it.next();
+ int elemHash = (elem != null ? elem.hashCode() : 0);
+ Object newVal = resolveValue(beanName, bean, elem);
+ int newValHash = (newVal != null ? newVal.hashCode() : 0);
+ newContent.add(newVal);
+ entriesModified = entriesModified
+ || (newVal != elem || newValHash != elemHash);
+ }
+ return entriesModified ? newContent : value;
+ } else {
+ // log.debug(beanName + ": " + value.getClass() + " : " + value);
+ return value;
+ }
+
+ }
+
+ private String resolveString(String beanName, Object bean, String strVal) {
+ // in case <null/> is passed
+ if (strVal == null)
+ return null;
+
+ String value = parseStringValue(bean, strVal, new HashSet<String>());
+
+ if (value == null)
+ throw new SlcException("Could not resolve placeholder '" + strVal
+ + "' in bean '" + beanName + "'");
+
+ return (value.equals(nullValue) ? null : value);
+ }
+
+ public void setPlaceholderPrefix(String placeholderPrefix) {
+ this.placeholderPrefix = placeholderPrefix;
+ }
+
+ public void setPlaceholderSuffix(String placeholderSuffix) {
+ this.placeholderSuffix = placeholderSuffix;
+ }
+
+ public void setNullValue(String nullValue) {
+ this.nullValue = nullValue;
+ }
+
+ public void setInstantiationManager(
+ InstantiationManager instantiationManager) {
+ this.instantiationManager = instantiationManager;
+ }
+
+ public void setExecutionContext(ExecutionContext executionContext) {
+ this.executionContext = executionContext;
+ }
+
+ //
+ // Following methods hacked from the internals of
+ // PropertyPlaceholderConfigurer
+ //
+
+ protected String parseStringValue(Object bean, String strVal,
+ Set<String> visitedPlaceholders)
+ throws BeanDefinitionStoreException {
+
+ // in case <null/> is passed
+ if (strVal == null)
+ return null;
+
+ StringBuffer buf = new StringBuffer(strVal);
+
+ int startIndex = strVal.indexOf(placeholderPrefix);
+ while (startIndex != -1) {
+ int endIndex = findPlaceholderEndIndex(buf, startIndex);
+ if (endIndex != -1) {
+ String placeholder = buf.substring(startIndex
+ + placeholderPrefix.length(), endIndex);
+ if (!visitedPlaceholders.add(placeholder)) {
+ throw new BeanDefinitionStoreException(
+ "Circular placeholder reference '" + placeholder
+ + "' in property definitions");
+ }
+ // Recursive invocation, parsing placeholders contained in
+ // the placeholder key.
+ placeholder = parseStringValue(bean, placeholder,
+ visitedPlaceholders);
+ // Now obtain the value for the fully resolved key...
+ String propVal = resolvePlaceholder(bean, placeholder);
+ if (propVal != null) {
+ // Recursive invocation, parsing placeholders contained
+ // in the
+ // previously resolved placeholder value.
+ propVal = parseStringValue(bean, propVal,
+ visitedPlaceholders);
+ buf.replace(startIndex,
+ endIndex + placeholderSuffix.length(), propVal);
+ if (log.isTraceEnabled()) {
+ log.trace("Resolved placeholder '" + placeholder + "'");
+ }
+ startIndex = buf.indexOf(placeholderPrefix, startIndex
+ + propVal.length());
+ } else {
+ throw new BeanDefinitionStoreException(
+ "Could not resolve placeholder '" + placeholder
+ + "'");
+ }
+ visitedPlaceholders.remove(placeholder);
+ } else {
+ startIndex = -1;
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
+ int index = startIndex + placeholderPrefix.length();
+ int withinNestedPlaceholder = 0;
+ while (index < buf.length()) {
+ if (StringUtils.substringMatch(buf, index, placeholderSuffix)) {
+ if (withinNestedPlaceholder > 0) {
+ withinNestedPlaceholder--;
+ index = index + placeholderSuffix.length();
+ } else {
+ return index;
+ }
+ } else if (StringUtils
+ .substringMatch(buf, index, placeholderPrefix)) {
+ withinNestedPlaceholder++;
+ index = index + placeholderPrefix.length();
+ } else {
+ index++;
+ }
+ }
+ return -1;
+ }
+
+}