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 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
;
31 * When Spring beans are instantiated with this scope, the same instance is
32 * reused across an execution.
34 public class ExecutionScope
implements Scope
{
35 private final static Log log
= LogFactory
.getLog(ExecutionScope
.class);
37 private final ThreadLocal
<ExecutionStack
> executionStack
= new ThreadLocal
<ExecutionStack
>();
38 public final ThreadLocal
<String
> executionStackBeanName
= new ThreadLocal
<String
>();
40 private final ThreadLocal
<ExecutionContext
> executionContext
= new ThreadLocal
<ExecutionContext
>();
41 private final ThreadLocal
<String
> executionContextBeanName
= new ThreadLocal
<String
>();
43 public Object
get(String name
, ObjectFactory objectFactory
) {
44 if (log
.isTraceEnabled())
45 log
.debug("Get execution scoped bean " + name
);
48 if (executionStackBeanName
.get() != null
49 && name
.equals(executionStackBeanName
.get())) {
50 return executionStack
.get();
53 if (executionContextBeanName
.get() != null
54 && name
.equals(executionContextBeanName
.get())) {
55 return executionContext
.get();
58 // execution context must be defined first
59 if (executionContext
.get() == null) {
60 Object obj
= objectFactory
.getObject();
61 if (obj
instanceof ExecutionContext
) {
62 return dealWithSpecialScopedObject(name
, executionContext
,
63 executionContextBeanName
, (ExecutionContext
) obj
);
65 // TODO: use execution context wrapper
66 throw new SlcException("No execution context has been defined.");
70 // for other scoped objects, an executions stack must be available
71 if (executionStack
.get() == null) {
72 Object obj
= objectFactory
.getObject();
73 if (obj
instanceof ExecutionStack
) {
74 return dealWithSpecialScopedObject(name
, executionStack
,
75 executionStackBeanName
, (ExecutionStack
) obj
);
77 throw new SlcException("No execution stack has been defined.");
81 // see if the execution stack already knows the object
82 Object obj
= executionStack
.get().findScopedObject(name
);
84 obj
= objectFactory
.getObject();
85 if (obj
instanceof ExecutionContext
)
86 throw new SlcException(
87 "Only one execution context can be defined per thread");
88 if (obj
instanceof ExecutionStack
)
89 throw new SlcException(
90 "Only one execution stack can be defined per thread");
92 checkForbiddenClasses(obj
);
94 executionStack
.get().addScopedObject(name
, obj
);
100 protected <T
> T
dealWithSpecialScopedObject(String name
,
101 ThreadLocal
<T
> threadLocal
,
102 ThreadLocal
<String
> threadLocalBeanName
, T newObj
) {
104 T obj
= threadLocal
.get();
107 threadLocal
.set(obj
);
108 threadLocalBeanName
.set(name
);
109 if (log
.isTraceEnabled()) {
110 log
.debug(obj
.getClass() + " instantiated. (beanName=" + name
115 throw new SlcException("Only one scoped " + obj
.getClass()
116 + " can be defined per thread");
121 protected void checkForbiddenClasses(Object obj
) {
122 Class
<?
> clss
= obj
.getClass();
123 if (ExecutionFlow
.class.isAssignableFrom(clss
)
124 || ExecutionSpec
.class.isAssignableFrom(clss
)) {
125 throw new UnsupportedException("Execution scoped object", clss
);
129 public String
getConversationId() {
130 // TODO: is it the most relevant?
131 return executionContext
.get().getUuid();
134 public void registerDestructionCallback(String name
, Runnable callback
) {
135 // TODO: implement it
136 // throw new UnsupportedOperationException();
139 public Object
remove(String name
) {
140 if (log
.isDebugEnabled())
141 log
.debug("Remove object " + name
);
142 throw new UnsupportedOperationException();
145 public Object
resolveContextualObject(String key
) {
146 return executionContext
.get().getVariable(key
);