]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java
Document and improve execution model
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / ExecutionScope.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
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
17 package org.argeo.slc.core.execution;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.argeo.slc.SlcException;
22 import org.argeo.slc.UnsupportedException;
23 import org.argeo.slc.execution.ExecutionContext;
24 import org.argeo.slc.execution.ExecutionFlow;
25 import org.argeo.slc.execution.ExecutionSpec;
26 import org.argeo.slc.execution.ExecutionStack;
27 import org.springframework.beans.factory.ObjectFactory;
28 import org.springframework.beans.factory.config.Scope;
29
30 public class ExecutionScope implements Scope {
31 private final static Log log = LogFactory.getLog(ExecutionScope.class);
32
33 private final ThreadLocal<ExecutionStack> executionStack = new ThreadLocal<ExecutionStack>();
34 public final ThreadLocal<String> executionStackBeanName = new ThreadLocal<String>();
35
36 private final ThreadLocal<ExecutionContext> executionContext = new ThreadLocal<ExecutionContext>();
37 private final ThreadLocal<String> executionContextBeanName = new ThreadLocal<String>();
38
39 public Object get(String name, ObjectFactory objectFactory) {
40 if (log.isTraceEnabled())
41 log.debug("Get execution scoped bean " + name);
42
43 // shortcuts
44 if (executionStackBeanName.get() != null
45 && name.equals(executionStackBeanName.get())) {
46 return executionStack.get();
47 }
48
49 if (executionContextBeanName.get() != null
50 && name.equals(executionContextBeanName.get())) {
51 return executionContext.get();
52 }
53
54 // execution context must be defined first
55 if (executionContext.get() == null) {
56 Object obj = objectFactory.getObject();
57 if (obj instanceof ExecutionContext) {
58 return dealWithSpecialScopedObject(name, executionContext,
59 executionContextBeanName, (ExecutionContext) obj);
60 } else {
61 // TODO: use execution context wrapper
62 throw new SlcException("No execution context has been defined.");
63 }
64 }
65
66 // for other scoped objects, an executions stack must be available
67 if (executionStack.get() == null) {
68 Object obj = objectFactory.getObject();
69 if (obj instanceof ExecutionStack) {
70 return dealWithSpecialScopedObject(name, executionStack,
71 executionStackBeanName, (ExecutionStack) obj);
72 } else {
73 throw new SlcException("No execution stack has been defined.");
74 }
75 }
76
77 // see if the execution stack already knows the object
78 Object obj = executionStack.get().findScopedObject(name);
79 if (obj == null) {
80 obj = objectFactory.getObject();
81 if (obj instanceof ExecutionContext)
82 throw new SlcException(
83 "Only one execution context can be defined per thread");
84 if (obj instanceof ExecutionStack)
85 throw new SlcException(
86 "Only one execution stack can be defined per thread");
87
88 checkForbiddenClasses(obj);
89
90 executionStack.get().addScopedObject(name, obj);
91 }
92 return obj;
93
94 }
95
96 protected <T> T dealWithSpecialScopedObject(String name,
97 ThreadLocal<T> threadLocal,
98 ThreadLocal<String> threadLocalBeanName, T newObj) {
99
100 T obj = threadLocal.get();
101 if (obj == null) {
102 obj = newObj;
103 threadLocal.set(obj);
104 threadLocalBeanName.set(name);
105 if (log.isTraceEnabled()) {
106 log.debug(obj.getClass() + " instantiated. (beanName=" + name
107 + ")");
108 }
109 return obj;
110 } else {
111 throw new SlcException("Only one scoped " + obj.getClass()
112 + " can be defined per thread");
113 }
114
115 }
116
117 protected void checkForbiddenClasses(Object obj) {
118 Class<?> clss = obj.getClass();
119 if (ExecutionFlow.class.isAssignableFrom(clss)
120 || ExecutionSpec.class.isAssignableFrom(clss)) {
121 throw new UnsupportedException("Execution scoped object", clss);
122 }
123 }
124
125 public String getConversationId() {
126 // TODO: is it the most relevant?
127 return executionContext.get().getUuid();
128 }
129
130 public void registerDestructionCallback(String name, Runnable callback) {
131 // TODO: implement it
132 // throw new UnsupportedOperationException();
133 }
134
135 public Object remove(String name) {
136 if (log.isDebugEnabled())
137 log.debug("Remove object " + name);
138 throw new UnsupportedOperationException();
139 }
140
141 public Object resolveContextualObject(String key) {
142 return executionContext.get().getVariable(key);
143 }
144
145 }