2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.argeo
.slc
.core
.execution
.generator
;
19 import java
.util
.HashMap
;
21 import org
.apache
.commons
.logging
.Log
;
22 import org
.apache
.commons
.logging
.LogFactory
;
23 import org
.argeo
.slc
.SlcException
;
24 import org
.springframework
.aop
.scope
.ScopedProxyUtils
;
25 import org
.springframework
.beans
.BeansException
;
26 import org
.springframework
.beans
.MutablePropertyValues
;
27 import org
.springframework
.beans
.factory
.config
.BeanDefinitionHolder
;
28 import org
.springframework
.beans
.factory
.config
.BeanFactoryPostProcessor
;
29 import org
.springframework
.beans
.factory
.config
.ConfigurableListableBeanFactory
;
30 import org
.springframework
.beans
.factory
.config
.RuntimeBeanReference
;
31 import org
.springframework
.beans
.factory
.support
.BeanDefinitionRegistry
;
32 import org
.springframework
.beans
.factory
.support
.GenericBeanDefinition
;
33 import org
.springframework
.core
.Ordered
;
36 * Generates <code>ExecutionFlows</code> and <code>Runnables</code> as
37 * beans in the Spring Application Context.
38 * Called by the Application Context as a <code>BeanFactoryPostProcessor</code>.
39 * Two kinds of beans are generated:
40 * <code>RunnableCallFlow</code>, calling a list of <code>Runnables</code> from the
41 * Application Context after configuring the <code>ExecutionContext</code>,
42 * and outputs of a <code>RunnableFactory</code>.
44 public class ExecutionFlowGenerator
implements BeanFactoryPostProcessor
,
47 private final Log log
= LogFactory
.getLog(getClass());
50 * Source providing a list of <code>RunnableCallFlowDescriptor</code>
51 * used to create <code>RunnableCallFlow</code> and a list of
52 * <code>RunnableDataNode</code> used to create any kind of flow via a factory
54 protected ExecutionFlowGeneratorSource source
;
57 * Factory used to create Runnables in the Application context from
58 * the <code>RunnableDataNode</code> provided from the source.
60 protected RunnableFactory runnableFactory
;
63 * Bean name of the <code>ExecutionContext</code>.
64 * Used to provide the created <code>RunnableCallFlow</code> beans
65 * with a <code>RuntimeBeanReference</code> to
66 * the <code>ExecutionContext</code>
68 private String executionContextBeanName
= "executionContext";
71 * Bean name of the context values Map.
72 * A bean of class HashMap is created with this name, and a
73 * <code>RuntimeBeanReference</code> is provided to the created
74 * <code>RunnableCallFlow</code> beans.
76 private String contextValuesBeanName
= "executionFlowGenerator.contextValues";
79 * Prefix added to the bean names defined in each
80 * <code>RunnableCallFlowDescriptor</code>
82 private String flowBeanNamesPrefix
= "";
84 private int order
= Ordered
.HIGHEST_PRECEDENCE
;
86 public void postProcessBeanFactory(
87 ConfigurableListableBeanFactory beanFactory
) throws BeansException
{
89 // assert that the beanFactory is a BeanDefinitionRegistry
90 if (!(beanFactory
instanceof BeanDefinitionRegistry
)) {
91 throw new SlcException("Can only work on "
92 + BeanDefinitionRegistry
.class);
95 // add bean for the Context Values Map
96 createAndRegisterContextValuesBean((BeanDefinitionRegistry
) beanFactory
);
98 // add beans for each RunnableDataNode
99 for(RunnableDataNode node
: source
.getRunnableDataNodes()) {
100 runnableFactory
.createAndRegisterRunnable(node
, (BeanDefinitionRegistry
) beanFactory
);
103 // add beans for each RunnableCallFlowDescriptor of the source to the application context
104 for (RunnableCallFlowDescriptor descriptor
: source
105 .getRunnableCallFlowDescriptors()) {
106 createAndRegisterFlowFor(descriptor
, (BeanDefinitionRegistry
) beanFactory
);
111 * Creates a <code>RunnableCallFlow</code> bean
112 * for a <code>RunnableCallFlowDescriptor</code> and registers
113 * it in the <code>BeanDefinitionRegistry</code>
114 * @param flowDescriptor
117 private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor
, BeanDefinitionRegistry registry
) {
118 // create the flow bean
119 GenericBeanDefinition flowBean
= new GenericBeanDefinition();
120 flowBean
.setBeanClass(RunnableCallFlow
.class);
122 String beanName
= flowBeanNamesPrefix
+ flowDescriptor
.getBeanName();
124 MutablePropertyValues mpv
= new MutablePropertyValues();
125 mpv
.addPropertyValue("runnableCalls", flowDescriptor
.getRunnableCalls());
126 mpv
.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName
));
128 mpv
.addPropertyValue("name", beanName
);
129 mpv
.addPropertyValue("path", flowDescriptor
.getPath());
131 mpv
.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName
));
133 flowBean
.setPropertyValues(mpv
);
136 if(log
.isDebugEnabled()) {
137 log
.debug("Registering bean definition for RunnableCallFlow " + beanName
);
139 registry
.registerBeanDefinition(beanName
, flowBean
);
143 * Creates the Context Values bean and register it in the
144 * <code>BeanDefinitionRegistry</code>
147 private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry
) {
148 GenericBeanDefinition contextValuesBean
= new GenericBeanDefinition();
149 contextValuesBean
.setBeanClass(HashMap
.class);
151 BeanDefinitionHolder bdh
= ScopedProxyUtils
.createScopedProxy(new BeanDefinitionHolder(contextValuesBean
, contextValuesBeanName
), registry
, true);
152 registry
.registerBeanDefinition(contextValuesBeanName
, bdh
.getBeanDefinition());
155 public int getOrder() {
159 public void setOrder(int order
) {
163 public void setSource(ExecutionFlowGeneratorSource source
) {
164 this.source
= source
;
167 public void setRunnableFactory(RunnableFactory runnableFactory
) {
168 this.runnableFactory
= runnableFactory
;
171 public void setExecutionContextBeanName(String executionContextBeanName
) {
172 this.executionContextBeanName
= executionContextBeanName
;
175 public void setContextValuesBeanName(String contextValuesBeanName
) {
176 this.contextValuesBeanName
= contextValuesBeanName
;
179 public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix
) {
180 this.flowBeanNamesPrefix
= flowBeanNamesPrefix
;