2 * Copyright (C) 2007-2012 Argeo GmbH
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.
16 package org
.argeo
.slc
.core
.execution
;
18 import org
.apache
.commons
.logging
.Log
;
19 import org
.apache
.commons
.logging
.LogFactory
;
20 import org
.argeo
.slc
.SlcException
;
21 import org
.argeo
.slc
.UnsupportedException
;
22 import org
.argeo
.slc
.execution
.ExecutionContext
;
23 import org
.argeo
.slc
.execution
.ExecutionFlow
;
24 import org
.argeo
.slc
.execution
.ExecutionSpec
;
25 import org
.argeo
.slc
.execution
.ExecutionStack
;
26 import org
.springframework
.beans
.factory
.ObjectFactory
;
27 import org
.springframework
.beans
.factory
.config
.Scope
;
30 * When Spring beans are instantiated with this scope, the same instance is
31 * reused across an execution.
33 public class ExecutionScope
implements Scope
{
34 private final static Log log
= LogFactory
.getLog(ExecutionScope
.class);
36 private final ThreadLocal
<ExecutionStack
> executionStack
= new ThreadLocal
<ExecutionStack
>();
37 public final ThreadLocal
<String
> executionStackBeanName
= new ThreadLocal
<String
>();
39 private final ThreadLocal
<ExecutionContext
> executionContext
= new ThreadLocal
<ExecutionContext
>();
40 private final ThreadLocal
<String
> executionContextBeanName
= new ThreadLocal
<String
>();
42 public Object
get(String name
, ObjectFactory objectFactory
) {
43 if (log
.isTraceEnabled())
44 log
.debug("Get execution scoped bean " + name
);
47 if (executionStackBeanName
.get() != null
48 && name
.equals(executionStackBeanName
.get())) {
49 return executionStack
.get();
52 if (executionContextBeanName
.get() != null
53 && name
.equals(executionContextBeanName
.get())) {
54 return executionContext
.get();
57 // execution context must be defined first
58 if (executionContext
.get() == null) {
59 Object obj
= objectFactory
.getObject();
60 if (obj
instanceof ExecutionContext
) {
61 return dealWithSpecialScopedObject(name
, executionContext
,
62 executionContextBeanName
, (ExecutionContext
) obj
);
64 // TODO: use execution context wrapper
65 throw new SlcException("No execution context has been defined.");
69 // for other scoped objects, an executions stack must be available
70 if (executionStack
.get() == null) {
71 Object obj
= objectFactory
.getObject();
72 if (obj
instanceof ExecutionStack
) {
73 return dealWithSpecialScopedObject(name
, executionStack
,
74 executionStackBeanName
, (ExecutionStack
) obj
);
76 throw new SlcException("No execution stack has been defined.");
80 // see if the execution stack already knows the object
81 Object obj
= executionStack
.get().findScopedObject(name
);
83 obj
= objectFactory
.getObject();
84 if (obj
instanceof ExecutionContext
)
85 throw new SlcException(
86 "Only one execution context can be defined per thread");
87 if (obj
instanceof ExecutionStack
)
88 throw new SlcException(
89 "Only one execution stack can be defined per thread");
91 checkForbiddenClasses(obj
);
93 executionStack
.get().addScopedObject(name
, obj
);
99 protected <T
> T
dealWithSpecialScopedObject(String name
,
100 ThreadLocal
<T
> threadLocal
,
101 ThreadLocal
<String
> threadLocalBeanName
, T newObj
) {
103 T obj
= threadLocal
.get();
106 threadLocal
.set(obj
);
107 threadLocalBeanName
.set(name
);
108 if (log
.isTraceEnabled()) {
109 log
.debug(obj
.getClass() + " instantiated. (beanName=" + name
114 throw new SlcException("Only one scoped " + obj
.getClass()
115 + " can be defined per thread");
120 protected void checkForbiddenClasses(Object obj
) {
121 Class
<?
> clss
= obj
.getClass();
122 if (ExecutionFlow
.class.isAssignableFrom(clss
)
123 || ExecutionSpec
.class.isAssignableFrom(clss
)) {
124 throw new UnsupportedException("Execution scoped object", clss
);
128 public String
getConversationId() {
129 // TODO: is it the most relevant?
130 return executionContext
.get().getUuid();
133 public void registerDestructionCallback(String name
, Runnable callback
) {
134 if (Thread
.currentThread() instanceof ExecutionThread
) {
135 ExecutionThread executionThread
= (ExecutionThread
) Thread
137 executionThread
.registerDestructionCallback(name
, callback
);
141 public Object
remove(String name
) {
142 if (log
.isDebugEnabled())
143 log
.debug("Remove object " + name
);
144 throw new UnsupportedOperationException();
147 public Object
resolveContextualObject(String key
) {
148 return executionContext
.get().getVariable(key
);