1 package org
.argeo
.slc
.core
.execution
;
3 import org
.apache
.commons
.logging
.Log
;
4 import org
.apache
.commons
.logging
.LogFactory
;
5 import org
.argeo
.slc
.SlcException
;
6 import org
.argeo
.slc
.UnsupportedException
;
7 import org
.argeo
.slc
.execution
.ExecutionContext
;
8 import org
.argeo
.slc
.execution
.ExecutionFlow
;
9 import org
.argeo
.slc
.execution
.ExecutionSpec
;
10 import org
.argeo
.slc
.execution
.ExecutionStack
;
11 import org
.argeo
.slc
.runtime
.ExecutionThread
;
12 import org
.springframework
.beans
.factory
.ObjectFactory
;
13 import org
.springframework
.beans
.factory
.config
.Scope
;
16 * When Spring beans are instantiated with this scope, the same instance is
17 * reused across an execution.
19 public class ExecutionScope
implements Scope
{
20 private final static Log log
= LogFactory
.getLog(ExecutionScope
.class);
22 private final ThreadLocal
<ExecutionStack
> executionStack
= new ThreadLocal
<ExecutionStack
>();
23 public final ThreadLocal
<String
> executionStackBeanName
= new ThreadLocal
<String
>();
25 private final ThreadLocal
<ExecutionContext
> executionContext
= new ThreadLocal
<ExecutionContext
>();
26 private final ThreadLocal
<String
> executionContextBeanName
= new ThreadLocal
<String
>();
28 public Object
get(String name
, ObjectFactory
<?
> objectFactory
) {
29 if (log
.isTraceEnabled())
30 log
.debug("Get execution scoped bean " + name
);
33 if (executionStackBeanName
.get() != null
34 && name
.equals(executionStackBeanName
.get())) {
35 return executionStack
.get();
38 if (executionContextBeanName
.get() != null
39 && name
.equals(executionContextBeanName
.get())) {
40 return executionContext
.get();
43 // execution context must be defined first
44 if (executionContext
.get() == null) {
45 Object obj
= objectFactory
.getObject();
46 if (obj
instanceof ExecutionContext
) {
47 return dealWithSpecialScopedObject(name
, executionContext
,
48 executionContextBeanName
, (ExecutionContext
) obj
);
50 // TODO: use execution context wrapper
51 throw new SlcException("No execution context has been defined.");
55 // for other scoped objects, an executions stack must be available
56 if (executionStack
.get() == null) {
57 Object obj
= objectFactory
.getObject();
58 if (obj
instanceof ExecutionStack
) {
59 return dealWithSpecialScopedObject(name
, executionStack
,
60 executionStackBeanName
, (ExecutionStack
) obj
);
62 throw new SlcException("No execution stack has been defined.");
66 // see if the execution stack already knows the object
67 Object obj
= executionStack
.get().findScopedObject(name
);
69 obj
= objectFactory
.getObject();
70 if (obj
instanceof ExecutionContext
)
71 throw new SlcException(
72 "Only one execution context can be defined per thread");
73 if (obj
instanceof ExecutionStack
)
74 throw new SlcException(
75 "Only one execution stack can be defined per thread");
77 checkForbiddenClasses(obj
);
79 executionStack
.get().addScopedObject(name
, obj
);
85 protected <T
> T
dealWithSpecialScopedObject(String name
,
86 ThreadLocal
<T
> threadLocal
,
87 ThreadLocal
<String
> threadLocalBeanName
, T newObj
) {
89 T obj
= threadLocal
.get();
93 threadLocalBeanName
.set(name
);
94 if (log
.isTraceEnabled()) {
95 log
.debug(obj
.getClass() + " instantiated. (beanName=" + name
100 throw new SlcException("Only one scoped " + obj
.getClass()
101 + " can be defined per thread");
106 protected void checkForbiddenClasses(Object obj
) {
107 Class
<?
> clss
= obj
.getClass();
108 if (ExecutionFlow
.class.isAssignableFrom(clss
)
109 || ExecutionSpec
.class.isAssignableFrom(clss
)) {
110 throw new UnsupportedException("Execution scoped object", clss
);
114 public String
getConversationId() {
115 // TODO: is it the most relevant?
116 return executionContext
.get().getUuid();
119 public void registerDestructionCallback(String name
, Runnable callback
) {
120 if (Thread
.currentThread() instanceof ExecutionThread
) {
121 ExecutionThread executionThread
= (ExecutionThread
) Thread
123 executionThread
.registerDestructionCallback(name
, callback
);
127 public Object
remove(String name
) {
128 if (log
.isDebugEnabled())
129 log
.debug("Remove object " + name
);
130 throw new UnsupportedOperationException();
133 public Object
resolveContextualObject(String key
) {
134 return executionContext
.get().getVariable(key
);