2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org
.argeo
.slc
.core
.execution
;
19 import java
.util
.Comparator
;
20 import java
.util
.HashMap
;
22 import java
.util
.SortedSet
;
23 import java
.util
.TreeMap
;
24 import java
.util
.TreeSet
;
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
;
46 public class DefaultExecutionFlowDescriptorConverter
implements
47 ExecutionFlowDescriptorConverter
, ApplicationContextAware
{
48 public final static String REF_VALUE_TYPE_BEAN_NAME
= "beanName";
50 /** Workaround for https://www.spartadn.com/bugzilla/show_bug.cgi?id=206 */
51 private final static String REF_VALUE_INTERNAL
= "[internal]";
53 private final static Log log
= LogFactory
54 .getLog(DefaultExecutionFlowDescriptorConverter
.class);
56 private ApplicationContext applicationContext
;
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
65 if (executionSpec
== null && log
.isTraceEnabled())
66 log
.warn("Execution spec is null for " + executionFlowDescriptor
);
68 if (values
!= null && executionSpec
!= null) {
69 values
: for (String key
: values
.keySet()) {
70 ExecutionSpecAttribute attribute
= executionSpec
71 .getAttributes().get(key
);
73 if (attribute
.getIsFrozen())
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
88 // String executionSpecName = executionSpec.getName();
89 // ExecutionSpec localSpec = (ExecutionSpec)
91 // .getBean(executionSpecName);
92 // RefSpecAttribute localAttr = (RefSpecAttribute)
94 // .getAttributes().get(key);
95 // Class<?> targetClass = localAttr.getTargetClass();
97 // String primitiveType = PrimitiveUtils
98 // .classAsType(targetClass);
99 String primitiveType
= null;
100 if (primitiveType
!= null) {
102 String ref
= refValue
.getRef();
103 Object obj
= PrimitiveUtils
.convert(primitiveType
,
105 convertedValues
.put(key
, obj
);
107 String ref
= refValue
.getRef();
108 if (ref
!= null && !ref
.equals(REF_VALUE_INTERNAL
)) {
110 if (applicationContext
.containsBean(ref
)) {
111 obj
= applicationContext
.getBean(ref
);
113 // FIXME: hack in order to pass primitive
116 convertedValues
.put(key
, obj
);
118 log
.warn("Cannot interpret " + refValue
);
121 } else if (PrimitiveUtils
.typeAsClass(type
) != null) {
122 String ref
= refValue
.getRef();
123 Object obj
= PrimitiveUtils
.convert(type
, ref
);
124 convertedValues
.put(key
, obj
);
126 throw new UnsupportedException("Ref value type",
132 return convertedValues
;
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
);
142 Assert
.notNull(executionFlow
.getName());
143 Assert
.state(name
.equals(executionFlow
.getName()));
145 ExecutionSpec executionSpec
= executionFlow
.getExecutionSpec();
146 Assert
.notNull(executionSpec
);
147 Assert
.notNull(executionSpec
.getName());
149 Map
<String
, Object
> values
= new TreeMap
<String
, Object
>();
150 for (String key
: executionSpec
.getAttributes().keySet()) {
151 ExecutionSpecAttribute attribute
= executionSpec
152 .getAttributes().get(key
);
154 if (attribute
instanceof PrimitiveSpecAttribute
) {
155 if (executionFlow
.isSetAsParameter(key
)) {
156 Object value
= executionFlow
.getParameter(key
);
157 PrimitiveValue primitiveValue
= new PrimitiveValue();
159 .setType(((PrimitiveSpecAttribute
) attribute
)
161 primitiveValue
.setValue(value
);
162 values
.put(key
, primitiveValue
);
164 // no need to add a primitive value if it is not set,
165 // all necessary information is in the spec
167 } else if (attribute
instanceof RefSpecAttribute
) {
168 if (attribute
.getIsFrozen()) {
169 values
.put(key
, new RefValue(REF_VALUE_INTERNAL
));
171 values
.put(key
, buildRefValue(
172 (RefSpecAttribute
) attribute
, executionFlow
,
175 throw new SlcException("Unkown spec attribute type "
176 + attribute
.getClass());
181 ExecutionFlowDescriptor efd
= new ExecutionFlowDescriptor(name
,
182 values
, executionSpec
);
183 if (executionFlow
.getPath() != null)
184 efd
.setPath(executionFlow
.getPath());
188 // Takes description from spring
189 BeanDefinition bd
= getBeanFactory().getBeanDefinition(name
);
190 efd
.setDescription(bd
.getDescription());
192 // Add execution spec if necessary
193 if (!md
.getExecutionSpecs().contains(executionSpec
))
194 md
.getExecutionSpecs().add(executionSpec
);
196 // Add execution flow
198 // md.getExecutionFlows().add(efd);
200 md
.getExecutionFlows().addAll(set
);
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());
216 refValue
.setType(primitiveType
);
220 if (executionFlow
.isSetAsParameter(key
)) {
222 Object value
= executionFlow
.getParameter(key
);
223 if (applicationContext
== null) {
225 .warn("No application context declared, cannot scan ref value.");
226 ref
= value
.toString();
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
)
243 if (obj
.equals(value
)) {
252 .warn("Cannot define reference for ref spec attribute "
259 + " If it is an inner bean consider put it frozen.");
260 ref
= REF_VALUE_INTERNAL
;
262 if (log
.isDebugEnabled())
264 + " is the reference for ref spec attribute "
265 + key
+ " in " + executionFlow
+ " (" + rsa
268 refValue
.setRef(ref
);
274 private ConfigurableListableBeanFactory
getBeanFactory() {
275 return ((ConfigurableApplicationContext
) applicationContext
)
279 /** Must be use within the execution application context */
280 public void setApplicationContext(ApplicationContext applicationContext
)
281 throws BeansException
{
282 this.applicationContext
= applicationContext
;
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()))
296 else if (o2
.getPath().startsWith(o1
.getPath()))
299 return o1
.getPath().compareTo(o2
.getPath());
300 } else if (!StringUtils
.hasText(o1
.getPath())
301 && StringUtils
.hasText(o2
.getPath())) {
303 } else if (StringUtils
.hasText(o1
.getPath())
304 && !StringUtils
.hasText(o2
.getPath())) {
306 } else if (!StringUtils
.hasText(o1
.getPath())
307 && !StringUtils
.hasText(o2
.getPath())) {
308 return o1
.getName().compareTo(o2
.getName());