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