Skip to content

Commit bd43ca1

Browse files
farnettofmbenhassine
authored andcommitted
Fix TARGET_NAME_PREFIX in StepScope
Resolves #3936
1 parent c7b5b01 commit bd43ca1

File tree

3 files changed

+240
-178
lines changed

3 files changed

+240
-178
lines changed
Lines changed: 176 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,176 @@
1-
/*
2-
* Copyright 2006-2013 the original author or authors.
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-
* https://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-
package org.springframework.batch.core.scope;
17-
18-
import org.apache.commons.logging.Log;
19-
import org.apache.commons.logging.LogFactory;
20-
import org.springframework.batch.core.scope.context.StepContext;
21-
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
22-
import org.springframework.beans.BeanWrapper;
23-
import org.springframework.beans.BeanWrapperImpl;
24-
import org.springframework.beans.factory.ObjectFactory;
25-
import org.springframework.beans.factory.config.Scope;
26-
27-
/**
28-
* Scope for step context. Objects in this scope use the Spring container as an
29-
* object factory, so there is only one instance of such a bean per executing
30-
* step. All objects in this scope are <aop:scoped-proxy/> (no need to
31-
* decorate the bean definitions).<br>
32-
* <br>
33-
*
34-
* In addition, support is provided for late binding of references accessible
35-
* from the {@link StepContext} using #{..} placeholders. Using this feature,
36-
* bean properties can be pulled from the step or job execution context and the
37-
* job parameters. E.g.
38-
*
39-
* <pre>
40-
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
41-
* &lt;property name=&quot;parent&quot; ref=&quot;#{stepExecutionContext[helper]}&quot; /&gt;
42-
* &lt;/bean&gt;
43-
*
44-
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
45-
* &lt;property name=&quot;name&quot; value=&quot;#{stepExecutionContext['input.name']}&quot; /&gt;
46-
* &lt;/bean&gt;
47-
*
48-
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
49-
* &lt;property name=&quot;name&quot; value=&quot;#{jobParameters[input]}&quot; /&gt;
50-
* &lt;/bean&gt;
51-
*
52-
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
53-
* &lt;property name=&quot;name&quot; value=&quot;#{jobExecutionContext['input.stem']}.txt&quot; /&gt;
54-
* &lt;/bean&gt;
55-
* </pre>
56-
*
57-
* The {@link StepContext} is referenced using standard bean property paths (as
58-
* per {@link BeanWrapper}). The examples above all show the use of the Map
59-
* accessors provided as a convenience for step and job attributes.
60-
*
61-
* @author Dave Syer
62-
* @author Michael Minella
63-
* @since 2.0
64-
*/
65-
public class StepScope extends BatchScopeSupport {
66-
67-
private static final String TARGET_NAME_PREFIX = "stepScopedTarget.";
68-
69-
private Log logger = LogFactory.getLog(getClass());
70-
71-
private final Object mutex = new Object();
72-
73-
/**
74-
* Context key for clients to use for conversation identifier.
75-
*/
76-
public static final String ID_KEY = "STEP_IDENTIFIER";
77-
78-
public StepScope() {
79-
super();
80-
setName("step");
81-
}
82-
83-
/**
84-
* This will be used to resolve expressions in step-scoped beans.
85-
*/
86-
@Override
87-
public Object resolveContextualObject(String key) {
88-
StepContext context = getContext();
89-
// TODO: support for attributes as well maybe (setters not exposed yet
90-
// so not urgent).
91-
return new BeanWrapperImpl(context).getPropertyValue(key);
92-
}
93-
94-
/**
95-
* @see Scope#get(String, ObjectFactory)
96-
*/
97-
@Override
98-
public Object get(String name, ObjectFactory<?> objectFactory) {
99-
StepContext context = getContext();
100-
Object scopedObject = context.getAttribute(name);
101-
102-
if (scopedObject == null) {
103-
104-
synchronized (mutex) {
105-
scopedObject = context.getAttribute(name);
106-
if (scopedObject == null) {
107-
108-
if (logger.isDebugEnabled()) {
109-
logger.debug(String.format("Creating object in scope=%s, name=%s", this.getName(), name));
110-
}
111-
112-
113-
scopedObject = objectFactory.getObject();
114-
context.setAttribute(name, scopedObject);
115-
116-
}
117-
118-
}
119-
120-
}
121-
return scopedObject;
122-
}
123-
124-
/**
125-
* @see Scope#getConversationId()
126-
*/
127-
@Override
128-
public String getConversationId() {
129-
StepContext context = getContext();
130-
return context.getId();
131-
}
132-
133-
/**
134-
* @see Scope#registerDestructionCallback(String, Runnable)
135-
*/
136-
@Override
137-
public void registerDestructionCallback(String name, Runnable callback) {
138-
StepContext context = getContext();
139-
if (logger.isDebugEnabled()) {
140-
logger.debug(String.format("Registered destruction callback in scope=%s, name=%s", this.getName(), name));
141-
}
142-
context.registerDestructionCallback(name, callback);
143-
}
144-
145-
/**
146-
* @see Scope#remove(String)
147-
*/
148-
@Override
149-
public Object remove(String name) {
150-
StepContext context = getContext();
151-
if (logger.isDebugEnabled()) {
152-
logger.debug(String.format("Removing from scope=%s, name=%s", this.getName(), name));
153-
}
154-
return context.removeAttribute(name);
155-
}
156-
157-
/**
158-
* Get an attribute accessor in the form of a {@link StepContext} that can
159-
* be used to store scoped bean instances.
160-
*
161-
* @return the current step context which we can use as a scope storage
162-
* medium
163-
*/
164-
private StepContext getContext() {
165-
StepContext context = StepSynchronizationManager.getContext();
166-
if (context == null) {
167-
throw new IllegalStateException("No context holder available for step scope");
168-
}
169-
return context;
170-
}
171-
172-
@Override
173-
public String getTargetNamePrefix() {
174-
return TARGET_NAME_PREFIX;
175-
}
176-
}
1+
/*
2+
* Copyright 2006-2023 the original author or authors.
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+
* https://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+
package org.springframework.batch.core.scope;
17+
18+
import org.apache.commons.logging.Log;
19+
import org.apache.commons.logging.LogFactory;
20+
import org.springframework.batch.core.scope.context.StepContext;
21+
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
22+
import org.springframework.beans.BeanWrapper;
23+
import org.springframework.beans.BeanWrapperImpl;
24+
import org.springframework.beans.factory.ObjectFactory;
25+
import org.springframework.beans.factory.config.Scope;
26+
27+
/**
28+
* Scope for step context. Objects in this scope use the Spring container as an
29+
* object factory, so there is only one instance of such a bean per executing
30+
* step. All objects in this scope are &lt;aop:scoped-proxy/&gt; (no need to
31+
* decorate the bean definitions).<br>
32+
* <br>
33+
*
34+
* In addition, support is provided for late binding of references accessible
35+
* from the {@link StepContext} using #{..} placeholders. Using this feature,
36+
* bean properties can be pulled from the step or job execution context and the
37+
* job parameters. E.g.
38+
*
39+
* <pre>
40+
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
41+
* &lt;property name=&quot;parent&quot; ref=&quot;#{stepExecutionContext[helper]}&quot; /&gt;
42+
* &lt;/bean&gt;
43+
*
44+
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
45+
* &lt;property name=&quot;name&quot; value=&quot;#{stepExecutionContext['input.name']}&quot; /&gt;
46+
* &lt;/bean&gt;
47+
*
48+
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
49+
* &lt;property name=&quot;name&quot; value=&quot;#{jobParameters[input]}&quot; /&gt;
50+
* &lt;/bean&gt;
51+
*
52+
* &lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;step&quot;&gt;
53+
* &lt;property name=&quot;name&quot; value=&quot;#{jobExecutionContext['input.stem']}.txt&quot; /&gt;
54+
* &lt;/bean&gt;
55+
* </pre>
56+
*
57+
* The {@link StepContext} is referenced using standard bean property paths (as
58+
* per {@link BeanWrapper}). The examples above all show the use of the Map
59+
* accessors provided as a convenience for step and job attributes.
60+
*
61+
* @author Dave Syer
62+
* @author Michael Minella
63+
* @since 2.0
64+
*/
65+
public class StepScope extends BatchScopeSupport {
66+
67+
private static final String TARGET_NAME_PREFIX = "scopedTarget.";
68+
69+
private Log logger = LogFactory.getLog(getClass());
70+
71+
private final Object mutex = new Object();
72+
73+
/**
74+
* Context key for clients to use for conversation identifier.
75+
*/
76+
public static final String ID_KEY = "STEP_IDENTIFIER";
77+
78+
public StepScope() {
79+
super();
80+
setName("step");
81+
}
82+
83+
/**
84+
* This will be used to resolve expressions in step-scoped beans.
85+
*/
86+
@Override
87+
public Object resolveContextualObject(String key) {
88+
StepContext context = getContext();
89+
// TODO: support for attributes as well maybe (setters not exposed yet
90+
// so not urgent).
91+
return new BeanWrapperImpl(context).getPropertyValue(key);
92+
}
93+
94+
/**
95+
* @see Scope#get(String, ObjectFactory)
96+
*/
97+
@Override
98+
public Object get(String name, ObjectFactory<?> objectFactory) {
99+
StepContext context = getContext();
100+
Object scopedObject = context.getAttribute(name);
101+
102+
if (scopedObject == null) {
103+
104+
synchronized (mutex) {
105+
scopedObject = context.getAttribute(name);
106+
if (scopedObject == null) {
107+
108+
if (logger.isDebugEnabled()) {
109+
logger.debug(String.format("Creating object in scope=%s, name=%s", this.getName(), name));
110+
}
111+
112+
113+
scopedObject = objectFactory.getObject();
114+
context.setAttribute(name, scopedObject);
115+
116+
}
117+
118+
}
119+
120+
}
121+
return scopedObject;
122+
}
123+
124+
/**
125+
* @see Scope#getConversationId()
126+
*/
127+
@Override
128+
public String getConversationId() {
129+
StepContext context = getContext();
130+
return context.getId();
131+
}
132+
133+
/**
134+
* @see Scope#registerDestructionCallback(String, Runnable)
135+
*/
136+
@Override
137+
public void registerDestructionCallback(String name, Runnable callback) {
138+
StepContext context = getContext();
139+
if (logger.isDebugEnabled()) {
140+
logger.debug(String.format("Registered destruction callback in scope=%s, name=%s", this.getName(), name));
141+
}
142+
context.registerDestructionCallback(name, callback);
143+
}
144+
145+
/**
146+
* @see Scope#remove(String)
147+
*/
148+
@Override
149+
public Object remove(String name) {
150+
StepContext context = getContext();
151+
if (logger.isDebugEnabled()) {
152+
logger.debug(String.format("Removing from scope=%s, name=%s", this.getName(), name));
153+
}
154+
return context.removeAttribute(name);
155+
}
156+
157+
/**
158+
* Get an attribute accessor in the form of a {@link StepContext} that can
159+
* be used to store scoped bean instances.
160+
*
161+
* @return the current step context which we can use as a scope storage
162+
* medium
163+
*/
164+
private StepContext getContext() {
165+
StepContext context = StepSynchronizationManager.getContext();
166+
if (context == null) {
167+
throw new IllegalStateException("No context holder available for step scope");
168+
}
169+
return context;
170+
}
171+
172+
@Override
173+
public String getTargetNamePrefix() {
174+
return TARGET_NAME_PREFIX;
175+
}
176+
}

0 commit comments

Comments
 (0)