Skip to content

Commit 49758a2

Browse files
committed
Added convenience classes for typical JSR-236 setup in a Java EE 7 environment
Introduced DefaultManagedTaskExecutor, DefaultManagedTaskScheduler and DefaultManagedAwareThreadFactory classes, revised related javadoc, and deprecated unsupported JBossWorkManagerTaskExecutor in favor of JSR-236 setup on WildFly 8. Issue: SPR-8195
1 parent 00474ce commit 49758a2

File tree

10 files changed

+356
-51
lines changed

10 files changed

+356
-51
lines changed

spring-context-support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
1717
package org.springframework.scheduling.commonj;
1818

1919
import java.util.Collection;
20+
import java.util.concurrent.Callable;
2021
import java.util.concurrent.Future;
2122
import java.util.concurrent.FutureTask;
22-
import java.util.concurrent.Callable;
23-
2423
import javax.naming.NamingException;
2524

2625
import commonj.work.Work;
@@ -53,17 +52,9 @@
5352
* <p>The CommonJ WorkManager will usually be retrieved from the application
5453
* server's JNDI environment, as defined in the server's management console.
5554
*
56-
* <p><b>Note: At the time of this writing, the CommonJ WorkManager facility
57-
* is only supported on IBM WebSphere 6.0+ and BEA WebLogic 9.0+,
58-
* despite being such a crucial API for an application server.</b>
59-
* (There is a similar facility available on WebSphere 5.1 Enterprise,
60-
* though, which we will discuss below.)
61-
*
62-
* <p><b>On JBoss and GlassFish, a similar facility is available through
63-
* the JCA WorkManager.</b> See the
64-
* {@link org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor}
65-
* {@link org.springframework.jca.work.glassfish.GlassFishWorkManagerTaskExecutor}
66-
* classes which are the direct equivalent of this CommonJ adapter class.
55+
* <p>Note: On the upcoming EE 7 compliant versions of WebLogic and WebSphere, a
56+
* {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
57+
* should be preferred, following JSR-236 support in Java EE 7.
6758
*
6859
* @author Juergen Hoeller
6960
* @since 2.0
@@ -80,8 +71,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
8071

8172
/**
8273
* Specify the CommonJ WorkManager to delegate to.
83-
* <p>Alternatively, you can also specify the JNDI name
84-
* of the target WorkManager.
74+
* <p>Alternatively, you can also specify the JNDI name of the target WorkManager.
8575
* @see #setWorkManagerName
8676
*/
8777
public void setWorkManager(WorkManager workManager) {
@@ -90,9 +80,8 @@ public void setWorkManager(WorkManager workManager) {
9080

9181
/**
9282
* Set the JNDI name of the CommonJ WorkManager.
93-
* <p>This can either be a fully qualified JNDI name,
94-
* or the JNDI name relative to the current environment
95-
* naming context if "resourceRef" is set to "true".
83+
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
84+
* to the current environment naming context if "resourceRef" is set to "true".
9685
* @see #setWorkManager
9786
* @see #setResourceRef
9887
*/
@@ -177,30 +166,22 @@ public boolean prefersShortLivedTasks() {
177166
//-------------------------------------------------------------------------
178167

179168
@Override
180-
public WorkItem schedule(Work work)
181-
throws WorkException, IllegalArgumentException {
182-
169+
public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException {
183170
return this.workManager.schedule(work);
184171
}
185172

186173
@Override
187-
public WorkItem schedule(Work work, WorkListener workListener)
188-
throws WorkException, IllegalArgumentException {
189-
174+
public WorkItem schedule(Work work, WorkListener workListener) throws WorkException {
190175
return this.workManager.schedule(work, workListener);
191176
}
192177

193178
@Override
194-
public boolean waitForAll(Collection workItems, long timeout)
195-
throws InterruptedException, IllegalArgumentException {
196-
179+
public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException {
197180
return this.workManager.waitForAll(workItems, timeout);
198181
}
199182

200183
@Override
201-
public Collection waitForAny(Collection workItems, long timeout)
202-
throws InterruptedException, IllegalArgumentException {
203-
184+
public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException {
204185
return this.workManager.waitForAny(workItems, timeout);
205186
}
206187

spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838
*
3939
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedExecutorService}
4040
* in order to expose {@link javax.enterprise.concurrent.ManagedTask} adapters for it,
41-
* exposing a long-running hint based on {@link SchedulingAwareRunnable} and an
42-
* identity name based on the given Runnable/Callable's {@code toString()}.
41+
* exposing a long-running hint based on {@link SchedulingAwareRunnable} and an identity
42+
* name based on the given Runnable/Callable's {@code toString()}. For JSR-236 style
43+
* lookup in a Java EE 7 environment, consider using {@link DefaultManagedTaskExecutor}.
4344
*
4445
* <p>Note that there is a pre-built {@link ThreadPoolTaskExecutor} that allows
4546
* for defining a {@link java.util.concurrent.ThreadPoolExecutor} in bean style,
@@ -53,21 +54,22 @@
5354
* @see java.util.concurrent.ExecutorService
5455
* @see java.util.concurrent.ThreadPoolExecutor
5556
* @see java.util.concurrent.Executors
57+
* @see DefaultManagedTaskExecutor
5658
* @see ThreadPoolTaskExecutor
5759
*/
5860
public class ConcurrentTaskExecutor implements SchedulingTaskExecutor {
5961

60-
private static Class<?> managedExecutorService;
62+
private static Class<?> managedExecutorServiceClass;
6163

6264
static {
6365
try {
64-
managedExecutorService = ClassUtils.forName(
66+
managedExecutorServiceClass = ClassUtils.forName(
6567
"javax.enterprise.concurrent.ManagedExecutorService",
6668
ConcurrentTaskScheduler.class.getClassLoader());
6769
}
6870
catch (ClassNotFoundException ex) {
6971
// JSR-236 API not available...
70-
managedExecutorService = null;
72+
managedExecutorServiceClass = null;
7173
}
7274
}
7375

@@ -103,7 +105,7 @@ public ConcurrentTaskExecutor(Executor concurrentExecutor) {
103105
public final void setConcurrentExecutor(Executor concurrentExecutor) {
104106
if (concurrentExecutor != null) {
105107
this.concurrentExecutor = concurrentExecutor;
106-
if (managedExecutorService != null && managedExecutorService.isInstance(concurrentExecutor)) {
108+
if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) {
107109
this.adaptedExecutor = new ManagedTaskExecutorAdapter(concurrentExecutor);
108110
}
109111
else {

spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
* <p>Autodetects a JSR-236 {@link javax.enterprise.concurrent.ManagedScheduledExecutorService}
4545
* in order to use it for trigger-based scheduling if possible, instead of Spring's
4646
* local trigger management which ends up delegating to regular delay-based scheduling
47-
* against the {@code java.util.concurrent.ScheduledExecutorService} API.
47+
* against the {@code java.util.concurrent.ScheduledExecutorService} API. For JSR-236 style
48+
* lookup in a Java EE 7 environment, consider using {@link DefaultManagedTaskScheduler}.
4849
*
4950
* <p>Note that there is a pre-built {@link ThreadPoolTaskScheduler} that allows for
5051
* defining a {@link java.util.concurrent.ScheduledThreadPoolExecutor} in bean style,
@@ -58,21 +59,22 @@
5859
* @see java.util.concurrent.ScheduledExecutorService
5960
* @see java.util.concurrent.ScheduledThreadPoolExecutor
6061
* @see java.util.concurrent.Executors
62+
* @see DefaultManagedTaskScheduler
6163
* @see ThreadPoolTaskScheduler
6264
*/
6365
public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler {
6466

65-
private static Class<?> managedScheduledExecutorService;
67+
private static Class<?> managedScheduledExecutorServiceClass;
6668

6769
static {
6870
try {
69-
managedScheduledExecutorService = ClassUtils.forName(
71+
managedScheduledExecutorServiceClass = ClassUtils.forName(
7072
"javax.enterprise.concurrent.ManagedScheduledExecutorService",
7173
ConcurrentTaskScheduler.class.getClassLoader());
7274
}
7375
catch (ClassNotFoundException ex) {
7476
// JSR-236 API not available...
75-
managedScheduledExecutorService = null;
77+
managedScheduledExecutorServiceClass = null;
7678
}
7779
}
7880

@@ -139,8 +141,8 @@ public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorSer
139141
public final void setScheduledExecutor(ScheduledExecutorService scheduledExecutor) {
140142
if (scheduledExecutor != null) {
141143
this.scheduledExecutor = scheduledExecutor;
142-
this.enterpriseConcurrentScheduler = (managedScheduledExecutorService != null &&
143-
managedScheduledExecutorService.isInstance(scheduledExecutor));
144+
this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null &&
145+
managedScheduledExecutorServiceClass.isInstance(scheduledExecutor));
144146
}
145147
else {
146148
this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2002-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+
* 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.springframework.scheduling.concurrent;
18+
19+
import java.util.Properties;
20+
import java.util.concurrent.ThreadFactory;
21+
import javax.naming.NamingException;
22+
23+
import org.apache.commons.logging.Log;
24+
import org.apache.commons.logging.LogFactory;
25+
26+
import org.springframework.beans.factory.InitializingBean;
27+
import org.springframework.jndi.JndiLocatorDelegate;
28+
import org.springframework.jndi.JndiTemplate;
29+
30+
/**
31+
* JNDI-based variant of {@link CustomizableThreadFactory}, performing a default lookup
32+
* for JSR-236's "java:comp/DefaultManagedThreadFactory" in a Java EE 7 environment,
33+
* falling back to the local {@link CustomizableThreadFactory} setup if not found.
34+
*
35+
* <p>This is a convenient way to use managed threads when running in a Java EE 7 environment,
36+
* simply using regular local threads otherwise - without conditional setup (like profiles).
37+
*
38+
* <p>Note: This class is not strictly JSR-236 based; it can work with any regular
39+
* {@link java.util.concurrent.ThreadFactory} that can be found in JNDI.
40+
*
41+
* @author Juergen Hoeller
42+
* @since 4.0
43+
*/
44+
public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory implements InitializingBean {
45+
46+
protected final Log logger = LogFactory.getLog(getClass());
47+
48+
private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
49+
50+
private String jndiName = "java:comp/DefaultManagedThreadFactory";
51+
52+
private ThreadFactory threadFactory = this;
53+
54+
55+
/**
56+
* Set the JNDI template to use for JNDI lookups.
57+
* @see org.springframework.jndi.JndiAccessor#setJndiTemplate
58+
*/
59+
public void setJndiTemplate(JndiTemplate jndiTemplate) {
60+
this.jndiLocator.setJndiTemplate(jndiTemplate);
61+
}
62+
63+
/**
64+
* Set the JNDI environment to use for JNDI lookups.
65+
* @see org.springframework.jndi.JndiAccessor#setJndiEnvironment
66+
*/
67+
public void setJndiEnvironment(Properties jndiEnvironment) {
68+
this.jndiLocator.setJndiEnvironment(jndiEnvironment);
69+
}
70+
71+
/**
72+
* Set whether the lookup occurs in a J2EE container, i.e. if the prefix
73+
* "java:comp/env/" needs to be added if the JNDI name doesn't already
74+
* contain it. PersistenceAnnotationBeanPostProcessor's default is "true".
75+
* @see org.springframework.jndi.JndiLocatorSupport#setResourceRef
76+
*/
77+
public void setResourceRef(boolean resourceRef) {
78+
this.jndiLocator.setResourceRef(resourceRef);
79+
}
80+
81+
/**
82+
* Specify a JNDI name of the {@link java.util.concurrent.ThreadFactory} to delegate to,
83+
* replacing the default JNDI name "java:comp/DefaultManagedThreadFactory".
84+
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
85+
* to the current environment naming context if "resourceRef" is set to "true".
86+
* @see #setResourceRef
87+
*/
88+
public void setJndiName(String jndiName) {
89+
this.jndiName = jndiName;
90+
}
91+
92+
@Override
93+
public void afterPropertiesSet() throws NamingException {
94+
if (this.jndiName != null) {
95+
try {
96+
this.threadFactory = this.jndiLocator.lookup(this.jndiName, ThreadFactory.class);
97+
}
98+
catch (NamingException ex) {
99+
if (logger.isDebugEnabled()) {
100+
logger.debug("Failed to find [java:comp/DefaultManagedThreadFactory] in JNDI", ex);
101+
}
102+
if (logger.isInfoEnabled()) {
103+
logger.info("Could not find default managed thread factory in JNDI - " +
104+
"proceeding with default local thread factory");
105+
}
106+
}
107+
}
108+
}
109+
110+
111+
@Override
112+
public Thread newThread(Runnable runnable) {
113+
return this.threadFactory.newThread(runnable);
114+
}
115+
116+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2002-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+
* 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.springframework.scheduling.concurrent;
18+
19+
import java.util.Properties;
20+
import java.util.concurrent.Executor;
21+
import javax.naming.NamingException;
22+
23+
import org.springframework.beans.factory.InitializingBean;
24+
import org.springframework.jndi.JndiLocatorDelegate;
25+
import org.springframework.jndi.JndiTemplate;
26+
27+
/**
28+
* JNDI-based variant of {@link ConcurrentTaskExecutor}, performing a default lookup for
29+
* JSR-236's "java:comp/DefaultManagedExecutorService" in a Java EE 7 environment.
30+
*
31+
* <p>Note: This class is not strictly JSR-236 based; it can work with any regular
32+
* {@link java.util.concurrent.Executor} that can be found in JNDI.
33+
* The actual adapting to {@link javax.enterprise.concurrent.ManagedExecutorService}
34+
* happens in the base class {@link ConcurrentTaskExecutor} itself.
35+
*
36+
* @author Juergen Hoeller
37+
* @since 4.0
38+
*/
39+
public class DefaultManagedTaskExecutor extends ConcurrentTaskExecutor implements InitializingBean {
40+
41+
private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
42+
43+
private String jndiName = "java:comp/DefaultManagedExecutorService";
44+
45+
46+
/**
47+
* Set the JNDI template to use for JNDI lookups.
48+
* @see org.springframework.jndi.JndiAccessor#setJndiTemplate
49+
*/
50+
public void setJndiTemplate(JndiTemplate jndiTemplate) {
51+
this.jndiLocator.setJndiTemplate(jndiTemplate);
52+
}
53+
54+
/**
55+
* Set the JNDI environment to use for JNDI lookups.
56+
* @see org.springframework.jndi.JndiAccessor#setJndiEnvironment
57+
*/
58+
public void setJndiEnvironment(Properties jndiEnvironment) {
59+
this.jndiLocator.setJndiEnvironment(jndiEnvironment);
60+
}
61+
62+
/**
63+
* Set whether the lookup occurs in a J2EE container, i.e. if the prefix
64+
* "java:comp/env/" needs to be added if the JNDI name doesn't already
65+
* contain it. PersistenceAnnotationBeanPostProcessor's default is "true".
66+
* @see org.springframework.jndi.JndiLocatorSupport#setResourceRef
67+
*/
68+
public void setResourceRef(boolean resourceRef) {
69+
this.jndiLocator.setResourceRef(resourceRef);
70+
}
71+
72+
/**
73+
* Specify a JNDI name of the {@link java.util.concurrent.Executor} to delegate to,
74+
* replacing the default JNDI name "java:comp/DefaultManagedExecutorService".
75+
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
76+
* to the current environment naming context if "resourceRef" is set to "true".
77+
* @see #setConcurrentExecutor
78+
* @see #setResourceRef
79+
*/
80+
public void setJndiName(String jndiName) {
81+
this.jndiName = jndiName;
82+
}
83+
84+
@Override
85+
public void afterPropertiesSet() throws NamingException {
86+
if (this.jndiName != null) {
87+
setConcurrentExecutor(this.jndiLocator.lookup(this.jndiName, Executor.class));
88+
}
89+
}
90+
91+
}

0 commit comments

Comments
 (0)