X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.core%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fcore%2Fexecution%2FExecutionParameterPostProcessor.java;h=158bdd12e7368f2ae9c2841899f2558d61c89a85;hb=a0a151ee3a0aed29a3cb03d81e35d540ca9fdb03;hp=1bdd4f29a6d46a984443be4b213e7100bffbfda6;hpb=ee6c3543a0ff9403420ce6a9c647723269f14331;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java index 1bdd4f29a..158bdd12e 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2007-2012 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.argeo.slc.core.execution; import java.beans.PropertyDescriptor; @@ -5,57 +20,40 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Properties; 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.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.PropertyPlaceholderConfigurer; 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 ExecutionScope executionScope; + private ExecutionContext executionContext; private InstantiationManager instantiationManager; - - public InstantiationManager getInstantiationManager() { - return instantiationManager; - } - - public void setInstantiationManager( - InstantiationManager instantiationManager) { - this.instantiationManager = instantiationManager; - } - - public void setExecutionScope(ExecutionScope executionScope) { - this.executionScope = executionScope; - } - - public ExecutionContext getExecutionContext() { - return executionContext; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } private String placeholderPrefix = "@{"; private String placeholderSuffix = "}"; @@ -66,26 +64,145 @@ public class ExecutionParameterPostProcessor extends 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 - + // TODO: resolve at execution only if scope is execution + // TODO: deal with placeholders in RuntimeBeanReference and + // RuntimeBeanNameReference + MutablePropertyValues newPvs = new MutablePropertyValues(); - + boolean changesOccured = false; - - CustomPpc ppc = new CustomPpc(beanName); - - for(PropertyValue pv : pvs.getPropertyValues()) { - Object convertedValue = ppc.resolveValue(pv.getValue()); + + for (PropertyValue pv : pvs.getPropertyValues()) { + Object convertedValue = resolveValue(beanName, bean, pv.getValue()); newPvs.addPropertyValue(new PropertyValue(pv, convertedValue)); - if(convertedValue != pv.getValue()) { + 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; + } + + @SuppressWarnings(value = { "unchecked" }) + 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 newContent = new ManagedMap(); + 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 newContent = new ManagedList(); + 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 newContent = new ManagedSet(); + 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 is passed + if (strVal == null) + return null; + + String value = parseStringValue(bean, strVal, new HashSet()); + + 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; } @@ -97,108 +214,95 @@ public class ExecutionParameterPostProcessor extends public void setNullValue(String nullValue) { this.nullValue = nullValue; } - - private class CustomPpc extends PropertyPlaceholderConfigurer { - private final Properties props; - String beanName; - - public CustomPpc(String beanName) { - super(); - this.props = new Properties(); - this.beanName = beanName; - setPlaceholderPrefix(placeholderPrefix); - setPlaceholderSuffix(placeholderSuffix); - setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_NEVER); - } - /** Public access to the internals of PropertyPlaceholderConfigurer*/ - public String resolveString(String strVal) { - String value = parseStringValue(strVal, this.props, - new HashSet()); - return (value.equals(nullValue) ? null : value); - } - - public Object resolveValue(Object value) { - if (value instanceof TypedStringValue) { - TypedStringValue tsv = (TypedStringValue) value; - String originalValue = tsv.getValue(); - - String convertedValue = resolveString(originalValue); - return convertedValue.equals(originalValue) ? value : new TypedStringValue(convertedValue); - } - else if (value instanceof String) { - String originalValue = value.toString(); - String convertedValue = resolveString(originalValue); - return convertedValue.equals(originalValue) ? value : convertedValue; - } - else if (value instanceof ManagedMap) { - Map mapVal = (Map) value; - - Map newContent = new ManagedMap(); - 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(key); - int newKeyHash = (newKey != null ? newKey.hashCode() : 0); - Object val = entry.getValue(); - Object newVal = resolveValue(val); - newContent.put(newKey, newVal); - entriesModified = entriesModified || (newVal != val || newKey != key || newKeyHash != keyHash); + 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 visitedPlaceholders) + throws BeanDefinitionStoreException { + + // in case 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"); } - - return entriesModified ? newContent : value; - } - else if (value instanceof ManagedList) { - List listVal = (List) value; - List newContent = new ManagedList(); - boolean valueModified = false; - - for (int i = 0; i < listVal.size(); i++) { - Object elem = listVal.get(i); - Object newVal = resolveValue(elem); - newContent.add(newVal); - if (!ObjectUtils.nullSafeEquals(newVal, elem)) { - valueModified = true; + // 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 + "'"); } - } - return valueModified ? newContent : value; - } - else if (value instanceof ManagedSet) { - Set setVal = (Set) value; - Set newContent = new ManagedSet(); - boolean entriesModified = false; - for (Iterator it = setVal.iterator(); it.hasNext();) { - Object elem = it.next(); - int elemHash = (elem != null ? elem.hashCode() : 0); - Object newVal = resolveValue(elem); - int newValHash = (newVal != null ? newVal.hashCode() : 0); - newContent.add(newVal); - entriesModified = entriesModified || (newVal != elem || newValHash != elemHash); - } - return entriesModified ? newContent : value; + startIndex = buf.indexOf(placeholderPrefix, startIndex + + propVal.length()); + } else { + throw new BeanDefinitionStoreException( + "Could not resolve placeholder '" + placeholder + + "'"); + } + visitedPlaceholders.remove(placeholder); + } else { + startIndex = -1; } - else { - return value; - } } - @Override - protected String resolvePlaceholder(String placeholder, Properties props) { - if ((executionScope != null) - && (executionScope.hasExecutionContext())) { - Object obj = executionContext.findVariable(placeholder); - if(obj != null) { - return obj.toString(); + 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++; } - if (instantiationManager.isInFlowInitialization()) - return instantiationManager.getInitializingFlowParameter( - placeholder).toString(); - else - throw new SlcException("Could not resolve placeholder '" - + placeholder + "' in bean '" + beanName + "'"); } + return -1; } + }