]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java
Execution attribute of type ref now supported (break data model)
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / generator / ExecutionFlowGenerator.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 package org.argeo.slc.core.execution.generator;
18
19 import java.util.HashMap;
20
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;
34
35 /**
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>.
43 */
44 public class ExecutionFlowGenerator implements BeanFactoryPostProcessor,
45 Ordered {
46
47 private final Log log = LogFactory.getLog(getClass());
48
49 /**
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
53 */
54 protected ExecutionFlowGeneratorSource source;
55
56 /**
57 * Factory used to create Runnables in the Application context from
58 * the <code>RunnableDataNode</code> provided from the source.
59 */
60 protected RunnableFactory runnableFactory;
61
62 /**
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>
67 */
68 private String executionContextBeanName = "executionContext";
69
70 /**
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.
75 */
76 private String contextValuesBeanName = "executionFlowGenerator.contextValues";
77
78 /**
79 * Prefix added to the bean names defined in each
80 * <code>RunnableCallFlowDescriptor</code>
81 */
82 private String flowBeanNamesPrefix = "";
83
84 private int order = Ordered.HIGHEST_PRECEDENCE;
85
86 public void postProcessBeanFactory(
87 ConfigurableListableBeanFactory beanFactory) throws BeansException {
88
89 // assert that the beanFactory is a BeanDefinitionRegistry
90 if (!(beanFactory instanceof BeanDefinitionRegistry)) {
91 throw new SlcException("Can only work on "
92 + BeanDefinitionRegistry.class);
93 }
94
95 // add bean for the Context Values Map
96 createAndRegisterContextValuesBean((BeanDefinitionRegistry) beanFactory);
97
98 // add beans for each RunnableDataNode
99 for(RunnableDataNode node : source.getRunnableDataNodes()) {
100 runnableFactory.createAndRegisterRunnable(node, (BeanDefinitionRegistry) beanFactory);
101 }
102
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);
107 }
108 }
109
110 /**
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
115 * @param registry
116 */
117 private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor, BeanDefinitionRegistry registry) {
118 // create the flow bean
119 GenericBeanDefinition flowBean = new GenericBeanDefinition();
120 flowBean.setBeanClass(RunnableCallFlow.class);
121
122 String beanName = flowBeanNamesPrefix + flowDescriptor.getBeanName();
123
124 MutablePropertyValues mpv = new MutablePropertyValues();
125 mpv.addPropertyValue("runnableCalls", flowDescriptor.getRunnableCalls());
126 mpv.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName));
127
128 mpv.addPropertyValue("name", beanName);
129 mpv.addPropertyValue("path", flowDescriptor.getPath());
130
131 mpv.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName));
132
133 flowBean.setPropertyValues(mpv);
134
135 // register it
136 if(log.isDebugEnabled()) {
137 log.debug("Registering bean definition for RunnableCallFlow " + beanName);
138 }
139 registry.registerBeanDefinition(beanName, flowBean);
140 }
141
142 /**
143 * Creates the Context Values bean and register it in the
144 * <code>BeanDefinitionRegistry</code>
145 * @param registry
146 */
147 private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry) {
148 GenericBeanDefinition contextValuesBean = new GenericBeanDefinition();
149 contextValuesBean.setBeanClass(HashMap.class);
150
151 BeanDefinitionHolder bdh = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(contextValuesBean, contextValuesBeanName), registry, true);
152 registry.registerBeanDefinition(contextValuesBeanName, bdh.getBeanDefinition());
153 }
154
155 public int getOrder() {
156 return order;
157 }
158
159 public void setOrder(int order) {
160 this.order = order;
161 }
162
163 public void setSource(ExecutionFlowGeneratorSource source) {
164 this.source = source;
165 }
166
167 public void setRunnableFactory(RunnableFactory runnableFactory) {
168 this.runnableFactory = runnableFactory;
169 }
170
171 public void setExecutionContextBeanName(String executionContextBeanName) {
172 this.executionContextBeanName = executionContextBeanName;
173 }
174
175 public void setContextValuesBeanName(String contextValuesBeanName) {
176 this.contextValuesBeanName = contextValuesBeanName;
177 }
178
179 public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix) {
180 this.flowBeanNamesPrefix = flowBeanNamesPrefix;
181 }
182 }