]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java
Remove deprecated APIs
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / ExecutionParameterPostProcessor.java
index 1bdd4f29a6d46a984443be4b213e7100bffbfda6..158bdd12e7368f2ae9c2841899f2558d61c89a85 100644 (file)
@@ -1,3 +1,18 @@
+/*\r
+ * Copyright (C) 2007-2012 Mathieu Baudier\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
@@ -5,57 +20,40 @@ import java.util.HashSet;
 import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Map;\r
-import java.util.Properties;\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.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.PropertyPlaceholderConfigurer;\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
-\r
-       private ExecutionScope executionScope;\r
 \r
+       private ExecutionContext executionContext;\r
        private InstantiationManager instantiationManager;\r
-       \r
-       public InstantiationManager getInstantiationManager() {\r
-               return instantiationManager;\r
-       }\r
-\r
-       public void setInstantiationManager(\r
-                       InstantiationManager instantiationManager) {\r
-               this.instantiationManager = instantiationManager;\r
-       }\r
-\r
-       public void setExecutionScope(ExecutionScope executionScope) {\r
-               this.executionScope = executionScope;\r
-       }\r
-\r
-       public ExecutionContext getExecutionContext() {\r
-               return executionContext;\r
-       }\r
-\r
-       public void setExecutionContext(ExecutionContext executionContext) {\r
-               this.executionContext = executionContext;\r
-       }\r
 \r
        private String placeholderPrefix = "@{";\r
        private String placeholderSuffix = "}";\r
@@ -66,26 +64,145 @@ public class ExecutionParameterPostProcessor extends
                        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 RuntimeBeanNameReference\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
+\r
                boolean changesOccured = false;\r
-                               \r
-               CustomPpc ppc = new CustomPpc(beanName);\r
-               \r
-               for(PropertyValue pv : pvs.getPropertyValues()) {\r
-                       Object convertedValue = ppc.resolveValue(pv.getValue());\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
+                       if (convertedValue != pv.getValue()) {\r
                                changesOccured = true;\r
                        }\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
+       @SuppressWarnings(value = { "unchecked" })\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();\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();\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();\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
@@ -97,108 +214,95 @@ public class ExecutionParameterPostProcessor extends
        public void setNullValue(String nullValue) {\r
                this.nullValue = nullValue;\r
        }\r
-       \r
-       private class CustomPpc extends PropertyPlaceholderConfigurer {\r
-               private final Properties props;\r
-               String beanName;\r
-               \r
-               public CustomPpc(String beanName) {\r
-                       super();\r
-                       this.props = new Properties();\r
-                       this.beanName = beanName;\r
-                       setPlaceholderPrefix(placeholderPrefix);\r
-                       setPlaceholderSuffix(placeholderSuffix);\r
-                       setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_NEVER);\r
-               }\r
 \r
-               /** Public access to the internals of PropertyPlaceholderConfigurer*/\r
-               public String resolveString(String strVal) {\r
-                       String value = parseStringValue(strVal, this.props,\r
-                                       new HashSet<String>());\r
-                       return (value.equals(nullValue) ? null : value);\r
-               }\r
-               \r
-               public Object resolveValue(Object value) {\r
-                       if (value instanceof TypedStringValue) {\r
-                               TypedStringValue tsv = (TypedStringValue) value;\r
-                               String originalValue = tsv.getValue();\r
-\r
-                               String convertedValue = resolveString(originalValue);\r
-                               return convertedValue.equals(originalValue) ? value : new TypedStringValue(convertedValue);\r
-                       }\r
-                       else if (value instanceof String) {\r
-                               String originalValue = value.toString();                        \r
-                               String convertedValue = resolveString(originalValue);\r
-                               return convertedValue.equals(originalValue) ? value : convertedValue;\r
-                       }               \r
-                       else if (value instanceof ManagedMap) {\r
-                               Map mapVal = (Map) value;\r
-                               \r
-                               Map newContent = new ManagedMap();\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(key);\r
-                                       int newKeyHash = (newKey != null ? newKey.hashCode() : 0);\r
-                                       Object val = entry.getValue();\r
-                                       Object newVal = resolveValue(val);\r
-                                       newContent.put(newKey, newVal);\r
-                                       entriesModified = entriesModified || (newVal != val || newKey != key || newKeyHash != keyHash);\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
-                               \r
-                               return entriesModified ? newContent : value;\r
-                       }\r
-                       else if (value instanceof ManagedList) {\r
-                               List listVal = (List) value;\r
-                               List newContent = new ManagedList();\r
-                               boolean valueModified = false;\r
-                               \r
-                               for (int i = 0; i < listVal.size(); i++) {\r
-                                       Object elem = listVal.get(i);\r
-                                       Object newVal = resolveValue(elem);\r
-                                       newContent.add(newVal);\r
-                                       if (!ObjectUtils.nullSafeEquals(newVal, elem)) {\r
-                                               valueModified = true;\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
-                               }                       \r
-                               return valueModified ? newContent : value;\r
-                       }\r
-                       else if (value instanceof ManagedSet) {\r
-                               Set setVal = (Set) value;\r
-                               Set newContent = new ManagedSet();\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(elem);\r
-                                       int newValHash = (newVal != null ? newVal.hashCode() : 0);\r
-                                       newContent.add(newVal);\r
-                                       entriesModified = entriesModified || (newVal != elem || newValHash != elemHash);\r
-                               }       \r
-                               return entriesModified ? newContent : value;\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
-                       else {\r
-                               return value;\r
-                       }                       \r
                }\r
 \r
-               @Override\r
-               protected String resolvePlaceholder(String placeholder, Properties props) {                                             \r
-                       if ((executionScope != null)\r
-                                       && (executionScope.hasExecutionContext())) {\r
-                               Object obj = executionContext.findVariable(placeholder);\r
-                               if(obj != null) {\r
-                                       return obj.toString();\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
-                       if (instantiationManager.isInFlowInitialization())\r
-                               return instantiationManager.getInitializingFlowParameter(\r
-                                               placeholder).toString();\r
-                       else\r
-                               throw new SlcException("Could not resolve placeholder '" \r
-                                               + placeholder + "' in bean '" + beanName + "'");\r
                }\r
+               return -1;\r
        }\r
+\r
 }\r