]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java
Introduce JMX agent
[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
68 if (REF_VALUE_TYPE_BEAN_NAME.equals(refValue.getType())) {
69 String ref = refValue.getRef();
70 if (ref != null && !ref.equals(REF_VALUE_INTERNAL)) {
71 Object obj = applicationContext.getBean(refValue
72 .getRef());
73 convertedValues.put(key, obj);
74 } else {
75 log.warn("Cannot interpret " + refValue);
76 }
77 } else {
78 throw new UnsupportedException("Ref value type",
79 refValue.getType());
80 }
81 }
82 }
83 }
84 return convertedValues;
85 }
86
87 public void addFlowsToDescriptor(ExecutionModuleDescriptor md,
88 Map<String, ExecutionFlow> executionFlows) {
89 SortedSet<ExecutionFlowDescriptor> set = new TreeSet<ExecutionFlowDescriptor>(
90 new ExecutionFlowDescriptorComparator());
91 for (String name : executionFlows.keySet()) {
92 ExecutionFlow executionFlow = executionFlows.get(name);
93
94 Assert.notNull(executionFlow.getName());
95 Assert.state(name.equals(executionFlow.getName()));
96
97 ExecutionSpec executionSpec = executionFlow.getExecutionSpec();
98 Assert.notNull(executionSpec);
99 Assert.notNull(executionSpec.getName());
100
101 Map<String, Object> values = new TreeMap<String, Object>();
102 for (String key : executionSpec.getAttributes().keySet()) {
103 ExecutionSpecAttribute attribute = executionSpec
104 .getAttributes().get(key);
105
106 if (attribute instanceof PrimitiveSpecAttribute) {
107 if (executionFlow.isSetAsParameter(key)) {
108 Object value = executionFlow.getParameter(key);
109 PrimitiveValue primitiveValue = new PrimitiveValue();
110 primitiveValue
111 .setType(((PrimitiveSpecAttribute) attribute)
112 .getType());
113 primitiveValue.setValue(value);
114 values.put(key, primitiveValue);
115 } else {
116 // no need to add a primitive value if it is not set,
117 // all necessary information is in the spec
118 }
119 } else if (attribute instanceof RefSpecAttribute) {
120 if (attribute.getIsFrozen()) {
121 values.put(key, new RefValue(REF_VALUE_INTERNAL));
122 } else
123 values.put(key, buildRefValue(
124 (RefSpecAttribute) attribute, executionFlow,
125 key));
126 } else {
127 throw new SlcException("Unkown spec attribute type "
128 + attribute.getClass());
129 }
130
131 }
132
133 ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name,
134 values, executionSpec);
135 if (executionFlow.getPath() != null)
136 efd.setPath(executionFlow.getPath());
137 else
138 efd.setPath("");
139
140 // Takes description from spring
141 BeanDefinition bd = getBeanFactory().getBeanDefinition(name);
142 efd.setDescription(bd.getDescription());
143
144 // Add execution spec if necessary
145 if (!md.getExecutionSpecs().contains(executionSpec))
146 md.getExecutionSpecs().add(executionSpec);
147
148 // Add execution flow
149 set.add(efd);
150 // md.getExecutionFlows().add(efd);
151 }
152 md.getExecutionFlows().addAll(set);
153 }
154
155 @SuppressWarnings(value = { "unchecked" })
156 protected RefValue buildRefValue(RefSpecAttribute rsa,
157 ExecutionFlow executionFlow, String key) {
158 RefValue refValue = new RefValue();
159 refValue.setType(REF_VALUE_TYPE_BEAN_NAME);
160
161 if (executionFlow.isSetAsParameter(key)) {
162 String ref = null;
163 Object value = executionFlow.getParameter(key);
164 if (applicationContext == null) {
165 log
166 .warn("No application context declared, cannot scan ref value.");
167 ref = value.toString();
168 } else {
169
170 // look for a ref to the value
171 Map<String, Object> beans = getBeanFactory().getBeansOfType(
172 rsa.getTargetClass(), false, false);
173 // TODO: also check scoped beans
174 beans: for (String beanName : beans.keySet()) {
175 Object obj = beans.get(beanName);
176 if (value instanceof ScopedObject) {
177 // don't call methods of the target of the scope
178 if (obj instanceof ScopedObject)
179 if (value == obj) {
180 ref = beanName;
181 break beans;
182 }
183 } else {
184 if (obj.equals(value)) {
185 ref = beanName;
186 break beans;
187 }
188 }
189 }
190 }
191 if (ref == null) {
192 log.warn("Cannot define reference for ref spec attribute "
193 + key + " in " + executionFlow + " (" + rsa + ")."
194 + " If it is an inner bean consider put it frozen.");
195 ref = REF_VALUE_INTERNAL;
196 } else {
197 if (log.isDebugEnabled())
198 log.debug(ref + " is the reference for ref spec attribute "
199 + key + " in " + executionFlow + " (" + rsa + ")");
200 }
201 refValue.setRef(ref);
202 }
203 return refValue;
204 }
205
206 private ConfigurableListableBeanFactory getBeanFactory() {
207 return ((ConfigurableApplicationContext) applicationContext)
208 .getBeanFactory();
209 }
210
211 /** Must be use within the execution application context */
212 public void setApplicationContext(ApplicationContext applicationContext)
213 throws BeansException {
214 this.applicationContext = applicationContext;
215 }
216
217 private static class ExecutionFlowDescriptorComparator implements
218 Comparator<ExecutionFlowDescriptor> {
219 public int compare(ExecutionFlowDescriptor o1,
220 ExecutionFlowDescriptor o2) {
221 // TODO: write unit tests for this
222 if (StringUtils.hasText(o1.getPath())
223 && StringUtils.hasText(o2.getPath())) {
224 if (o1.getPath().equals(o2.getPath()))
225 return o1.getName().compareTo(o2.getName());
226 else if (o1.getPath().startsWith(o2.getPath()))
227 return -1;
228 else if (o2.getPath().startsWith(o1.getPath()))
229 return 1;
230 else
231 return o1.getPath().compareTo(o2.getPath());
232 } else if (!StringUtils.hasText(o1.getPath())
233 && StringUtils.hasText(o2.getPath())) {
234 return 1;
235 } else if (StringUtils.hasText(o1.getPath())
236 && !StringUtils.hasText(o2.getPath())) {
237 return -1;
238 } else if (!StringUtils.hasText(o1.getPath())
239 && !StringUtils.hasText(o2.getPath())) {
240 return o1.getName().compareTo(o2.getName());
241 } else {
242 return 0;
243 }
244 }
245
246 }
247 }