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