]> git.argeo.org Git - gpl/argeo-slc.git/blob - legacy/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionScope.java
Adapt to changes in Argeo Commons
[gpl/argeo-slc.git] / legacy / org.argeo.slc.spring / src / org / argeo / slc / core / execution / ExecutionScope.java
1 package org.argeo.slc.core.execution;
2
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;
14
15 /**
16 * When Spring beans are instantiated with this scope, the same instance is
17 * reused across an execution.
18 */
19 public class ExecutionScope implements Scope {
20 private final static Log log = LogFactory.getLog(ExecutionScope.class);
21
22 private final ThreadLocal<ExecutionStack> executionStack = new ThreadLocal<ExecutionStack>();
23 public final ThreadLocal<String> executionStackBeanName = new ThreadLocal<String>();
24
25 private final ThreadLocal<ExecutionContext> executionContext = new ThreadLocal<ExecutionContext>();
26 private final ThreadLocal<String> executionContextBeanName = new ThreadLocal<String>();
27
28 public Object get(String name, ObjectFactory<?> objectFactory) {
29 if (log.isTraceEnabled())
30 log.debug("Get execution scoped bean " + name);
31
32 // shortcuts
33 if (executionStackBeanName.get() != null
34 && name.equals(executionStackBeanName.get())) {
35 return executionStack.get();
36 }
37
38 if (executionContextBeanName.get() != null
39 && name.equals(executionContextBeanName.get())) {
40 return executionContext.get();
41 }
42
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);
49 } else {
50 // TODO: use execution context wrapper
51 throw new SlcException("No execution context has been defined.");
52 }
53 }
54
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);
61 } else {
62 throw new SlcException("No execution stack has been defined.");
63 }
64 }
65
66 // see if the execution stack already knows the object
67 Object obj = executionStack.get().findScopedObject(name);
68 if (obj == null) {
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");
76
77 checkForbiddenClasses(obj);
78
79 executionStack.get().addScopedObject(name, obj);
80 }
81 return obj;
82
83 }
84
85 protected <T> T dealWithSpecialScopedObject(String name,
86 ThreadLocal<T> threadLocal,
87 ThreadLocal<String> threadLocalBeanName, T newObj) {
88
89 T obj = threadLocal.get();
90 if (obj == null) {
91 obj = newObj;
92 threadLocal.set(obj);
93 threadLocalBeanName.set(name);
94 if (log.isTraceEnabled()) {
95 log.debug(obj.getClass() + " instantiated. (beanName=" + name
96 + ")");
97 }
98 return obj;
99 } else {
100 throw new SlcException("Only one scoped " + obj.getClass()
101 + " can be defined per thread");
102 }
103
104 }
105
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);
111 }
112 }
113
114 public String getConversationId() {
115 // TODO: is it the most relevant?
116 return executionContext.get().getUuid();
117 }
118
119 public void registerDestructionCallback(String name, Runnable callback) {
120 if (Thread.currentThread() instanceof ExecutionThread) {
121 ExecutionThread executionThread = (ExecutionThread) Thread
122 .currentThread();
123 executionThread.registerDestructionCallback(name, callback);
124 }
125 }
126
127 public Object remove(String name) {
128 if (log.isDebugEnabled())
129 log.debug("Remove object " + name);
130 throw new UnsupportedOperationException();
131 }
132
133 public Object resolveContextualObject(String key) {
134 return executionContext.get().getVariable(key);
135 }
136
137 }