]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java
Add license headers
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / DefaultExecutionFlowDescriptorConverter.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;
18
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.SortedSet;
23 import java.util.TreeMap;
24 import java.util.TreeSet;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.argeo.slc.SlcException;
29 import org.argeo.slc.UnsupportedException;
30 import org.argeo.slc.execution.ExecutionFlow;
31 import org.argeo.slc.execution.ExecutionFlowDescriptor;
32 import org.argeo.slc.execution.ExecutionFlowDescriptorConverter;
33 import org.argeo.slc.execution.ExecutionModuleDescriptor;
34 import org.argeo.slc.execution.ExecutionSpec;
35 import org.argeo.slc.execution.ExecutionSpecAttribute;
36 import org.springframework.aop.scope.ScopedObject;
37 import org.springframework.beans.BeansException;
38 import org.springframework.beans.factory.config.BeanDefinition;
39 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
40 import org.springframework.context.ApplicationContext;
41 import org.springframework.context.ApplicationContextAware;
42 import org.springframework.context.ConfigurableApplicationContext;
43 import org.springframework.util.Assert;
44 import org.springframework.util.StringUtils;
45
46 public class DefaultExecutionFlowDescriptorConverter implements
47 ExecutionFlowDescriptorConverter, ApplicationContextAware {
48 public final static String REF_VALUE_TYPE_BEAN_NAME = "beanName";
49
50 /** Workaround for https://www.spartadn.com/bugzilla/show_bug.cgi?id=206 */
51 private final static String REF_VALUE_INTERNAL = "[internal]";
52
53 private final static Log log = LogFactory
54 .getLog(DefaultExecutionFlowDescriptorConverter.class);
55
56 private ApplicationContext applicationContext;
57
58 public Map<String, Object> convertValues(
59 ExecutionFlowDescriptor executionFlowDescriptor) {
60 Map<String, Object> values = executionFlowDescriptor.getValues();
61 Map<String, Object> convertedValues = new HashMap<String, Object>();
62 ExecutionSpec executionSpec = executionFlowDescriptor
63 .getExecutionSpec();
64
65 if (executionSpec == null && log.isTraceEnabled())
66 log.warn("Execution spec is null for " + executionFlowDescriptor);
67
68 if (values != null && executionSpec != null) {
69 values: for (String key : values.keySet()) {
70 ExecutionSpecAttribute attribute = executionSpec
71 .getAttributes().get(key);
72
73 if (attribute.getIsFrozen())
74 continue values;
75
76 Object value = values.get(key);
77 if (value instanceof PrimitiveValue) {
78 PrimitiveValue primitiveValue = (PrimitiveValue) value;
79 // TODO: check class <=> type
80 convertedValues.put(key, primitiveValue.getValue());
81 } else if (value instanceof RefValue) {
82 RefValue refValue = (RefValue) value;
83 String type = refValue.getType();
84 if (REF_VALUE_TYPE_BEAN_NAME.equals(type)) {
85 // FIXME: UI should send all information about spec
86 // - targetClass
87 // - name
88 // String executionSpecName = executionSpec.getName();
89 // ExecutionSpec localSpec = (ExecutionSpec)
90 // applicationContext
91 // .getBean(executionSpecName);
92 // RefSpecAttribute localAttr = (RefSpecAttribute)
93 // localSpec
94 // .getAttributes().get(key);
95 // Class<?> targetClass = localAttr.getTargetClass();
96 //
97 // String primitiveType = PrimitiveUtils
98 // .classAsType(targetClass);
99 String primitiveType = null;
100 if (primitiveType != null) {
101 // not active
102 String ref = refValue.getRef();
103 Object obj = PrimitiveUtils.convert(primitiveType,
104 ref);
105 convertedValues.put(key, obj);
106 } else {
107 String ref = refValue.getRef();
108 if (ref != null && !ref.equals(REF_VALUE_INTERNAL)) {
109 Object obj = null;
110 if (applicationContext.containsBean(ref)) {
111 obj = applicationContext.getBean(ref);
112 } else {
113 // FIXME: hack in order to pass primitive
114 obj = ref;
115 }
116 convertedValues.put(key, obj);
117 } else {
118 log.warn("Cannot interpret " + refValue);
119 }
120 }
121 } else if (PrimitiveUtils.typeAsClass(type) != null) {
122 String ref = refValue.getRef();
123 Object obj = PrimitiveUtils.convert(type, ref);
124 convertedValues.put(key, obj);
125 } else {
126 throw new UnsupportedException("Ref value type",
127 refValue.getType());
128 }
129 }
130 }
131 }
132 return convertedValues;
133 }
134
135 public void addFlowsToDescriptor(ExecutionModuleDescriptor md,
136 Map<String, ExecutionFlow> executionFlows) {
137 SortedSet<ExecutionFlowDescriptor> set = new TreeSet<ExecutionFlowDescriptor>(
138 new ExecutionFlowDescriptorComparator());
139 for (String name : executionFlows.keySet()) {
140 ExecutionFlow executionFlow = executionFlows.get(name);
141
142 Assert.notNull(executionFlow.getName());
143 Assert.state(name.equals(executionFlow.getName()));
144
145 ExecutionSpec executionSpec = executionFlow.getExecutionSpec();
146 Assert.notNull(executionSpec);
147 Assert.notNull(executionSpec.getName());
148
149 Map<String, Object> values = new TreeMap<String, Object>();
150 for (String key : executionSpec.getAttributes().keySet()) {
151 ExecutionSpecAttribute attribute = executionSpec
152 .getAttributes().get(key);
153
154 if (attribute instanceof PrimitiveSpecAttribute) {
155 if (executionFlow.isSetAsParameter(key)) {
156 Object value = executionFlow.getParameter(key);
157 PrimitiveValue primitiveValue = new PrimitiveValue();
158 primitiveValue
159 .setType(((PrimitiveSpecAttribute) attribute)
160 .getType());
161 primitiveValue.setValue(value);
162 values.put(key, primitiveValue);
163 } else {
164 // no need to add a primitive value if it is not set,
165 // all necessary information is in the spec
166 }
167 } else if (attribute instanceof RefSpecAttribute) {
168 if (attribute.getIsFrozen()) {
169 values.put(key, new RefValue(REF_VALUE_INTERNAL));
170 } else
171 values.put(key, buildRefValue(
172 (RefSpecAttribute) attribute, executionFlow,
173 key));
174 } else {
175 throw new SlcException("Unkown spec attribute type "
176 + attribute.getClass());
177 }
178
179 }
180
181 ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name,
182 values, executionSpec);
183 if (executionFlow.getPath() != null)
184 efd.setPath(executionFlow.getPath());
185 else
186 efd.setPath("");
187
188 // Takes description from spring
189 BeanDefinition bd = getBeanFactory().getBeanDefinition(name);
190 efd.setDescription(bd.getDescription());
191
192 // Add execution spec if necessary
193 if (!md.getExecutionSpecs().contains(executionSpec))
194 md.getExecutionSpecs().add(executionSpec);
195
196 // Add execution flow
197 set.add(efd);
198 // md.getExecutionFlows().add(efd);
199 }
200 md.getExecutionFlows().addAll(set);
201 }
202
203 @SuppressWarnings(value = { "unchecked" })
204 protected RefValue buildRefValue(RefSpecAttribute rsa,
205 ExecutionFlow executionFlow, String key) {
206 RefValue refValue = new RefValue();
207 // FIXME: UI should be able to deal with other types
208 refValue.setType(REF_VALUE_TYPE_BEAN_NAME);
209 Class targetClass = rsa.getTargetClass();
210 String primitiveType = PrimitiveUtils.classAsType(targetClass);
211 if (primitiveType != null) {
212 if (executionFlow.isSetAsParameter(key)) {
213 Object value = executionFlow.getParameter(key);
214 refValue.setRef(value.toString());
215 }
216 refValue.setType(primitiveType);
217 return refValue;
218 } else {
219
220 if (executionFlow.isSetAsParameter(key)) {
221 String ref = null;
222 Object value = executionFlow.getParameter(key);
223 if (applicationContext == null) {
224 log
225 .warn("No application context declared, cannot scan ref value.");
226 ref = value.toString();
227 } else {
228
229 // look for a ref to the value
230 Map<String, Object> beans = getBeanFactory()
231 .getBeansOfType(targetClass, false, false);
232 // TODO: also check scoped beans
233 beans: for (String beanName : beans.keySet()) {
234 Object obj = beans.get(beanName);
235 if (value instanceof ScopedObject) {
236 // don't call methods of the target of the scope
237 if (obj instanceof ScopedObject)
238 if (value == obj) {
239 ref = beanName;
240 break beans;
241 }
242 } else {
243 if (obj.equals(value)) {
244 ref = beanName;
245 break beans;
246 }
247 }
248 }
249 }
250 if (ref == null) {
251 log
252 .warn("Cannot define reference for ref spec attribute "
253 + key
254 + " in "
255 + executionFlow
256 + " ("
257 + rsa
258 + ")."
259 + " If it is an inner bean consider put it frozen.");
260 ref = REF_VALUE_INTERNAL;
261 } else {
262 if (log.isDebugEnabled())
263 log.debug(ref
264 + " is the reference for ref spec attribute "
265 + key + " in " + executionFlow + " (" + rsa
266 + ")");
267 }
268 refValue.setRef(ref);
269 }
270 return refValue;
271 }
272 }
273
274 private ConfigurableListableBeanFactory getBeanFactory() {
275 return ((ConfigurableApplicationContext) applicationContext)
276 .getBeanFactory();
277 }
278
279 /** Must be use within the execution application context */
280 public void setApplicationContext(ApplicationContext applicationContext)
281 throws BeansException {
282 this.applicationContext = applicationContext;
283 }
284
285 private static class ExecutionFlowDescriptorComparator implements
286 Comparator<ExecutionFlowDescriptor> {
287 public int compare(ExecutionFlowDescriptor o1,
288 ExecutionFlowDescriptor o2) {
289 // TODO: write unit tests for this
290 if (StringUtils.hasText(o1.getPath())
291 && StringUtils.hasText(o2.getPath())) {
292 if (o1.getPath().equals(o2.getPath()))
293 return o1.getName().compareTo(o2.getName());
294 else if (o1.getPath().startsWith(o2.getPath()))
295 return -1;
296 else if (o2.getPath().startsWith(o1.getPath()))
297 return 1;
298 else
299 return o1.getPath().compareTo(o2.getPath());
300 } else if (!StringUtils.hasText(o1.getPath())
301 && StringUtils.hasText(o2.getPath())) {
302 return 1;
303 } else if (StringUtils.hasText(o1.getPath())
304 && !StringUtils.hasText(o2.getPath())) {
305 return -1;
306 } else if (!StringUtils.hasText(o1.getPath())
307 && !StringUtils.hasText(o2.getPath())) {
308 return o1.getName().compareTo(o2.getName());
309 } else {
310 return 0;
311 }
312 }
313
314 }
315 }