001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.scheduling.commonj;
018
019import java.util.Collection;
020import java.util.concurrent.Callable;
021import java.util.concurrent.Future;
022import java.util.concurrent.FutureTask;
023
024import javax.naming.NamingException;
025
026import commonj.work.Work;
027import commonj.work.WorkException;
028import commonj.work.WorkItem;
029import commonj.work.WorkListener;
030import commonj.work.WorkManager;
031import commonj.work.WorkRejectedException;
032
033import org.springframework.beans.factory.InitializingBean;
034import org.springframework.core.task.AsyncListenableTaskExecutor;
035import org.springframework.core.task.TaskDecorator;
036import org.springframework.core.task.TaskRejectedException;
037import org.springframework.jndi.JndiLocatorSupport;
038import org.springframework.lang.Nullable;
039import org.springframework.scheduling.SchedulingException;
040import org.springframework.scheduling.SchedulingTaskExecutor;
041import org.springframework.util.Assert;
042import org.springframework.util.concurrent.ListenableFuture;
043import org.springframework.util.concurrent.ListenableFutureTask;
044
045/**
046 * TaskExecutor implementation that delegates to a CommonJ WorkManager,
047 * implementing the {@link commonj.work.WorkManager} interface,
048 * which either needs to be specified as reference or through the JNDI name.
049 *
050 * <p><b>This is the central convenience class for setting up a
051 * CommonJ WorkManager in a Spring context.</b>
052 *
053 * <p>Also implements the CommonJ WorkManager interface itself, delegating all
054 * calls to the target WorkManager. Hence, a caller can choose whether it wants
055 * to talk to this executor through the Spring TaskExecutor interface or the
056 * CommonJ WorkManager interface.
057 *
058 * <p>The CommonJ WorkManager will usually be retrieved from the application
059 * server's JNDI environment, as defined in the server's management console.
060 *
061 * <p>Note: On EE 7/8 compliant versions of WebLogic and WebSphere, a
062 * {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
063 * should be preferred, following JSR-236 support in Java EE 7/8.
064 *
065 * @author Juergen Hoeller
066 * @since 2.0
067 * @deprecated as of 5.1, in favor of the EE 7/8 based
068 * {@link org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor}
069 */
070@Deprecated
071public class WorkManagerTaskExecutor extends JndiLocatorSupport
072                implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, WorkManager, InitializingBean {
073
074        @Nullable
075        private WorkManager workManager;
076
077        @Nullable
078        private String workManagerName;
079
080        @Nullable
081        private WorkListener workListener;
082
083        @Nullable
084        private TaskDecorator taskDecorator;
085
086
087        /**
088         * Specify the CommonJ WorkManager to delegate to.
089         * <p>Alternatively, you can also specify the JNDI name of the target WorkManager.
090         * @see #setWorkManagerName
091         */
092        public void setWorkManager(WorkManager workManager) {
093                this.workManager = workManager;
094        }
095
096        /**
097         * Set the JNDI name of the CommonJ WorkManager.
098         * <p>This can either be a fully qualified JNDI name, or the JNDI name relative
099         * to the current environment naming context if "resourceRef" is set to "true".
100         * @see #setWorkManager
101         * @see #setResourceRef
102         */
103        public void setWorkManagerName(String workManagerName) {
104                this.workManagerName = workManagerName;
105        }
106
107        /**
108         * Specify a CommonJ WorkListener to apply, if any.
109         * <p>This shared WorkListener instance will be passed on to the
110         * WorkManager by all {@link #execute} calls on this TaskExecutor.
111         */
112        public void setWorkListener(WorkListener workListener) {
113                this.workListener = workListener;
114        }
115
116        /**
117         * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
118         * about to be executed.
119         * <p>Note that such a decorator is not necessarily being applied to the
120         * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
121         * execution callback (which may be a wrapper around the user-supplied task).
122         * <p>The primary use case is to set some execution context around the task's
123         * invocation, or to provide some monitoring/statistics for task execution.
124         * <p><b>NOTE:</b> Exception handling in {@code TaskDecorator} implementations
125         * is limited to plain {@code Runnable} execution via {@code execute} calls.
126         * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
127         * {@code FutureTask} which does not propagate any exceptions; you might
128         * have to cast it and call {@code Future#get} to evaluate exceptions.
129         * @since 4.3
130         */
131        public void setTaskDecorator(TaskDecorator taskDecorator) {
132                this.taskDecorator = taskDecorator;
133        }
134
135        @Override
136        public void afterPropertiesSet() throws NamingException {
137                if (this.workManager == null) {
138                        if (this.workManagerName == null) {
139                                throw new IllegalArgumentException("Either 'workManager' or 'workManagerName' must be specified");
140                        }
141                        this.workManager = lookup(this.workManagerName, WorkManager.class);
142                }
143        }
144
145        private WorkManager obtainWorkManager() {
146                Assert.state(this.workManager != null, "No WorkManager specified");
147                return this.workManager;
148        }
149
150
151        //-------------------------------------------------------------------------
152        // Implementation of the Spring SchedulingTaskExecutor interface
153        //-------------------------------------------------------------------------
154
155        @Override
156        public void execute(Runnable task) {
157                Work work = new DelegatingWork(this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
158                try {
159                        if (this.workListener != null) {
160                                obtainWorkManager().schedule(work, this.workListener);
161                        }
162                        else {
163                                obtainWorkManager().schedule(work);
164                        }
165                }
166                catch (WorkRejectedException ex) {
167                        throw new TaskRejectedException("CommonJ WorkManager did not accept task: " + task, ex);
168                }
169                catch (WorkException ex) {
170                        throw new SchedulingException("Could not schedule task on CommonJ WorkManager", ex);
171                }
172        }
173
174        @Override
175        public void execute(Runnable task, long startTimeout) {
176                execute(task);
177        }
178
179        @Override
180        public Future<?> submit(Runnable task) {
181                FutureTask<Object> future = new FutureTask<>(task, null);
182                execute(future);
183                return future;
184        }
185
186        @Override
187        public <T> Future<T> submit(Callable<T> task) {
188                FutureTask<T> future = new FutureTask<>(task);
189                execute(future);
190                return future;
191        }
192
193        @Override
194        public ListenableFuture<?> submitListenable(Runnable task) {
195                ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
196                execute(future);
197                return future;
198        }
199
200        @Override
201        public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
202                ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
203                execute(future);
204                return future;
205        }
206
207
208        //-------------------------------------------------------------------------
209        // Implementation of the CommonJ WorkManager interface
210        //-------------------------------------------------------------------------
211
212        @Override
213        public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException {
214                return obtainWorkManager().schedule(work);
215        }
216
217        @Override
218        public WorkItem schedule(Work work, WorkListener workListener) throws WorkException {
219                return obtainWorkManager().schedule(work, workListener);
220        }
221
222        @Override
223        @SuppressWarnings("rawtypes")
224        public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException {
225                return obtainWorkManager().waitForAll(workItems, timeout);
226        }
227
228        @Override
229        @SuppressWarnings("rawtypes")
230        public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException {
231                return obtainWorkManager().waitForAny(workItems, timeout);
232        }
233
234}