1 package org
.argeo
.slc
.core
.execution
.generator
;
3 import java
.util
.HashMap
;
5 import org
.apache
.commons
.logging
.Log
;
6 import org
.apache
.commons
.logging
.LogFactory
;
7 import org
.argeo
.slc
.SlcException
;
8 import org
.springframework
.aop
.scope
.ScopedProxyUtils
;
9 import org
.springframework
.beans
.BeansException
;
10 import org
.springframework
.beans
.MutablePropertyValues
;
11 import org
.springframework
.beans
.factory
.config
.BeanDefinitionHolder
;
12 import org
.springframework
.beans
.factory
.config
.BeanFactoryPostProcessor
;
13 import org
.springframework
.beans
.factory
.config
.ConfigurableListableBeanFactory
;
14 import org
.springframework
.beans
.factory
.config
.RuntimeBeanReference
;
15 import org
.springframework
.beans
.factory
.support
.BeanDefinitionRegistry
;
16 import org
.springframework
.beans
.factory
.support
.GenericBeanDefinition
;
17 import org
.springframework
.core
.Ordered
;
20 * Generates <code>ExecutionFlows</code> and <code>Runnables</code> as
21 * beans in the Spring Application Context.
22 * Called by the Application Context as a <code>BeanFactoryPostProcessor</code>.
23 * Two kinds of beans are generated:
24 * <code>RunnableCallFlow</code>, calling a list of <code>Runnables</code> from the
25 * Application Context after configuring the <code>ExecutionContext</code>,
26 * and outputs of a <code>RunnableFactory</code>.
28 public class ExecutionFlowGenerator
implements BeanFactoryPostProcessor
,
31 private final Log log
= LogFactory
.getLog(getClass());
34 * Source providing a list of <code>RunnableCallFlowDescriptor</code>
35 * used to create <code>RunnableCallFlow</code> and a list of
36 * <code>RunnableDataNode</code> used to create any kind of flow via a factory
38 protected ExecutionFlowGeneratorSource source
;
41 * Factory used to create Runnables in the Application context from
42 * the <code>RunnableDataNode</code> provided from the source.
44 protected RunnableFactory runnableFactory
;
47 * Bean name of the <code>ExecutionContext</code>.
48 * Used to provide the created <code>RunnableCallFlow</code> beans
49 * with a <code>RuntimeBeanReference</code> to
50 * the <code>ExecutionContext</code>
52 private String executionContextBeanName
= "executionContext";
55 * Bean name of the context values Map.
56 * A bean of class HashMap is created with this name, and a
57 * <code>RuntimeBeanReference</code> is provided to the created
58 * <code>RunnableCallFlow</code> beans.
60 private String contextValuesBeanName
= "executionFlowGenerator.contextValues";
63 * Prefix added to the bean names defined in each
64 * <code>RunnableCallFlowDescriptor</code>
66 private String flowBeanNamesPrefix
= "";
68 private int order
= Ordered
.HIGHEST_PRECEDENCE
;
70 public void postProcessBeanFactory(
71 ConfigurableListableBeanFactory beanFactory
) throws BeansException
{
73 // assert that the beanFactory is a BeanDefinitionRegistry
74 if (!(beanFactory
instanceof BeanDefinitionRegistry
)) {
75 throw new SlcException("Can only work on "
76 + BeanDefinitionRegistry
.class);
79 // add bean for the Context Values Map
80 createAndRegisterContextValuesBean((BeanDefinitionRegistry
) beanFactory
);
82 // add beans for each RunnableDataNode
83 for(RunnableDataNode node
: source
.getRunnableDataNodes()) {
84 runnableFactory
.createAndRegisterRunnable(node
, (BeanDefinitionRegistry
) beanFactory
);
87 // add beans for each RunnableCallFlowDescriptor of the source to the application context
88 for (RunnableCallFlowDescriptor descriptor
: source
89 .getRunnableCallFlowDescriptors()) {
90 createAndRegisterFlowFor(descriptor
, (BeanDefinitionRegistry
) beanFactory
);
95 * Creates a <code>RunnableCallFlow</code> bean
96 * for a <code>RunnableCallFlowDescriptor</code> and registers
97 * it in the <code>BeanDefinitionRegistry</code>
98 * @param flowDescriptor
101 private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor
, BeanDefinitionRegistry registry
) {
102 // create the flow bean
103 GenericBeanDefinition flowBean
= new GenericBeanDefinition();
104 flowBean
.setBeanClass(RunnableCallFlow
.class);
106 String beanName
= flowBeanNamesPrefix
+ flowDescriptor
.getBeanName();
108 MutablePropertyValues mpv
= new MutablePropertyValues();
109 mpv
.addPropertyValue("runnableCalls", flowDescriptor
.getRunnableCalls());
110 mpv
.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName
));
112 mpv
.addPropertyValue("name", beanName
);
113 mpv
.addPropertyValue("path", flowDescriptor
.getPath());
115 mpv
.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName
));
117 flowBean
.setPropertyValues(mpv
);
120 if(log
.isDebugEnabled()) {
121 log
.debug("Registering bean definition for RunnableCallFlow " + beanName
);
123 registry
.registerBeanDefinition(beanName
, flowBean
);
127 * Creates the Context Values bean and register it in the
128 * <code>BeanDefinitionRegistry</code>
131 private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry
) {
132 GenericBeanDefinition contextValuesBean
= new GenericBeanDefinition();
133 contextValuesBean
.setBeanClass(HashMap
.class);
135 BeanDefinitionHolder bdh
= ScopedProxyUtils
.createScopedProxy(new BeanDefinitionHolder(contextValuesBean
, contextValuesBeanName
), registry
, true);
136 registry
.registerBeanDefinition(contextValuesBeanName
, bdh
.getBeanDefinition());
139 public int getOrder() {
143 public void setOrder(int order
) {
147 public void setSource(ExecutionFlowGeneratorSource source
) {
148 this.source
= source
;
151 public void setRunnableFactory(RunnableFactory runnableFactory
) {
152 this.runnableFactory
= runnableFactory
;
155 public void setExecutionContextBeanName(String executionContextBeanName
) {
156 this.executionContextBeanName
= executionContextBeanName
;
159 public void setContextValuesBeanName(String contextValuesBeanName
) {
160 this.contextValuesBeanName
= contextValuesBeanName
;
163 public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix
) {
164 this.flowBeanNamesPrefix
= flowBeanNamesPrefix
;