--- /dev/null
+/*\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.generator;\r
+\r
+import java.util.HashMap;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+import org.argeo.slc.SlcException;\r
+import org.springframework.aop.scope.ScopedProxyUtils;\r
+import org.springframework.beans.BeansException;\r
+import org.springframework.beans.MutablePropertyValues;\r
+import org.springframework.beans.factory.config.BeanDefinitionHolder;\r
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;\r
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\r
+import org.springframework.beans.factory.config.RuntimeBeanReference;\r
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;\r
+import org.springframework.beans.factory.support.GenericBeanDefinition;\r
+import org.springframework.core.Ordered;\r
+\r
+/**\r
+ * Generates <code>ExecutionFlows</code> and <code>Runnables</code> as\r
+ * beans in the Spring Application Context.\r
+ * Called by the Application Context as a <code>BeanFactoryPostProcessor</code>.\r
+ * Two kinds of beans are generated:\r
+ * <code>RunnableCallFlow</code>, calling a list of <code>Runnables</code> from the\r
+ * Application Context after configuring the <code>ExecutionContext</code>, \r
+ * and outputs of a <code>RunnableFactory</code>.\r
+ */\r
+public class ExecutionFlowGenerator implements BeanFactoryPostProcessor,\r
+ Ordered {\r
+ \r
+ private final Log log = LogFactory.getLog(getClass());\r
+\r
+ /**\r
+ * Source providing a list of <code>RunnableCallFlowDescriptor</code> \r
+ * used to create <code>RunnableCallFlow</code> and a list of \r
+ * <code>RunnableDataNode</code> used to create any kind of flow via a factory\r
+ */\r
+ protected ExecutionFlowGeneratorSource source;\r
+ \r
+ /**\r
+ * Factory used to create Runnables in the Application context from\r
+ * the <code>RunnableDataNode</code> provided from the source.\r
+ */\r
+ protected RunnableFactory runnableFactory;\r
+ \r
+ /**\r
+ * Bean name of the <code>ExecutionContext</code>.\r
+ * Used to provide the created <code>RunnableCallFlow</code> beans \r
+ * with a <code>RuntimeBeanReference</code> to\r
+ * the <code>ExecutionContext</code>\r
+ */\r
+ private String executionContextBeanName = "executionContext";\r
+ \r
+ /**\r
+ * Bean name of the context values Map.\r
+ * A bean of class HashMap is created with this name, and a \r
+ * <code>RuntimeBeanReference</code> is provided to the created\r
+ * <code>RunnableCallFlow</code> beans.\r
+ */\r
+ private String contextValuesBeanName = "executionFlowGenerator.contextValues";\r
+ \r
+ /**\r
+ * Prefix added to the bean names defined in each \r
+ * <code>RunnableCallFlowDescriptor</code>\r
+ */\r
+ private String flowBeanNamesPrefix = "";\r
+ \r
+ private int order = Ordered.HIGHEST_PRECEDENCE;\r
+ \r
+ public void postProcessBeanFactory(\r
+ ConfigurableListableBeanFactory beanFactory) throws BeansException {\r
+\r
+ // assert that the beanFactory is a BeanDefinitionRegistry\r
+ if (!(beanFactory instanceof BeanDefinitionRegistry)) {\r
+ throw new SlcException("Can only work on "\r
+ + BeanDefinitionRegistry.class);\r
+ } \r
+ \r
+ // add bean for the Context Values Map\r
+ createAndRegisterContextValuesBean((BeanDefinitionRegistry) beanFactory);\r
+ \r
+ // add beans for each RunnableDataNode\r
+ for(RunnableDataNode node : source.getRunnableDataNodes()) {\r
+ runnableFactory.createAndRegisterRunnable(node, (BeanDefinitionRegistry) beanFactory);\r
+ }\r
+ \r
+ // add beans for each RunnableCallFlowDescriptor of the source to the application context\r
+ for (RunnableCallFlowDescriptor descriptor : source\r
+ .getRunnableCallFlowDescriptors()) {\r
+ createAndRegisterFlowFor(descriptor, (BeanDefinitionRegistry) beanFactory);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates a <code>RunnableCallFlow</code> bean\r
+ * for a <code>RunnableCallFlowDescriptor</code> and registers \r
+ * it in the <code>BeanDefinitionRegistry</code>\r
+ * @param flowDescriptor\r
+ * @param registry\r
+ */\r
+ private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor, BeanDefinitionRegistry registry) {\r
+ // create the flow bean\r
+ GenericBeanDefinition flowBean = new GenericBeanDefinition();\r
+ flowBean.setBeanClass(RunnableCallFlow.class);\r
+ \r
+ String beanName = flowBeanNamesPrefix + flowDescriptor.getBeanName();\r
+ \r
+ MutablePropertyValues mpv = new MutablePropertyValues(); \r
+ mpv.addPropertyValue("runnableCalls", flowDescriptor.getRunnableCalls());\r
+ mpv.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName));\r
+ \r
+ mpv.addPropertyValue("name", beanName);\r
+ mpv.addPropertyValue("path", flowDescriptor.getPath());\r
+\r
+ mpv.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName));\r
+ \r
+ flowBean.setPropertyValues(mpv);\r
+ \r
+ // register it\r
+ if(log.isDebugEnabled()) {\r
+ log.debug("Registering bean definition for RunnableCallFlow " + beanName);\r
+ }\r
+ registry.registerBeanDefinition(beanName, flowBean);\r
+ }\r
+ \r
+ /**\r
+ * Creates the Context Values bean and register it in the\r
+ * <code>BeanDefinitionRegistry</code>\r
+ * @param registry\r
+ */\r
+ private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry) {\r
+ GenericBeanDefinition contextValuesBean = new GenericBeanDefinition();\r
+ contextValuesBean.setBeanClass(HashMap.class);\r
+ \r
+ BeanDefinitionHolder bdh = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(contextValuesBean, contextValuesBeanName), registry, true); \r
+ registry.registerBeanDefinition(contextValuesBeanName, bdh.getBeanDefinition()); \r
+ }\r
+ \r
+ public int getOrder() {\r
+ return order;\r
+ }\r
+\r
+ public void setOrder(int order) {\r
+ this.order = order;\r
+ }\r
+\r
+ public void setSource(ExecutionFlowGeneratorSource source) {\r
+ this.source = source;\r
+ }\r
+\r
+ public void setRunnableFactory(RunnableFactory runnableFactory) {\r
+ this.runnableFactory = runnableFactory;\r
+ }\r
+\r
+ public void setExecutionContextBeanName(String executionContextBeanName) {\r
+ this.executionContextBeanName = executionContextBeanName;\r
+ }\r
+\r
+ public void setContextValuesBeanName(String contextValuesBeanName) {\r
+ this.contextValuesBeanName = contextValuesBeanName;\r
+ }\r
+\r
+ public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix) {\r
+ this.flowBeanNamesPrefix = flowBeanNamesPrefix;\r
+ }\r
+}\r