001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.scheduling.commonj;
018:
019: import java.util.Collection;
020:
021: import javax.naming.NamingException;
022:
023: import commonj.work.Work;
024: import commonj.work.WorkException;
025: import commonj.work.WorkItem;
026: import commonj.work.WorkListener;
027: import commonj.work.WorkManager;
028: import commonj.work.WorkRejectedException;
029:
030: import org.springframework.beans.factory.InitializingBean;
031: import org.springframework.core.task.TaskRejectedException;
032: import org.springframework.jndi.JndiLocatorSupport;
033: import org.springframework.scheduling.SchedulingException;
034: import org.springframework.scheduling.SchedulingTaskExecutor;
035: import org.springframework.util.Assert;
036:
037: /**
038: * TaskExecutor implementation that delegates to a CommonJ WorkManager,
039: * implementing the {@link commonj.work.WorkManager} interface,
040: * which either needs to be specified as reference or through the JNDI name.
041: *
042: * <p><b>This is the central convenience class for setting up a
043: * CommonJ WorkManager in a Spring context.</b>
044: *
045: * <p>Also implements the CommonJ WorkManager interface itself, delegating all
046: * calls to the target WorkManager. Hence, a caller can choose whether it wants
047: * to talk to this executor through the Spring TaskExecutor interface or the
048: * CommonJ WorkManager interface.
049: *
050: * <p>The CommonJ WorkManager will usually be retrieved from the application
051: * server's JNDI environment, as defined in the server's management console.
052: *
053: * <p><b>Note: At the time of this writing, the CommonJ WorkManager facility
054: * is only supported on IBM WebSphere 6.0+ and BEA WebLogic 9.0+,
055: * despite being such a crucial API for an application server.</b>
056: * (There is a similar facility available on WebSphere 5.0 Enterprise,
057: * though, which we will discuss below.)
058: *
059: * <p>A similar facility is available on WebSphere 5.0/5.1, under the name
060: * "Asynch Beans". Its central interface is called WorkManager too and is
061: * also obtained from JNDI, just like a standard CommonJ WorkManager.
062: * However, this WorkManager variant is notably different: The central
063: * execution method is called "startWork" instead of "schedule",
064: * and takes a slightly different Work interface as parameter.
065: *
066: * <p>Support for this WebSphere 5 variant can be built with this class
067: * and its helper DelegatingWork as template: Call the WorkManager's
068: * <code>startWork(Work)</code> instead of <code>schedule(Work)</code>
069: * in the <code>execute(Runnable)</code> implementation. Furthermore,
070: * for simplicity's sake, drop the entire "Implementation of the CommonJ
071: * WorkManager interface" section (and the corresponding
072: * <code>implements WorkManager</code> clause at the class level).
073: * Of course, you also need to change all <code>commonj.work</code> imports in
074: * your WorkManagerTaskExecutor and DelegatingWork variants to the corresponding
075: * WebSphere API imports (<code>com.ibm.websphere.asynchbeans.WorkManager</code>
076: * and <code>com.ibm.websphere.asynchbeans.Work</code>, respectively).
077: * This should be sufficient to get a TaskExecutor adapter for WebSphere 5.
078: *
079: * @author Juergen Hoeller
080: * @since 2.0
081: */
082: public class WorkManagerTaskExecutor extends JndiLocatorSupport
083: implements SchedulingTaskExecutor, WorkManager,
084: InitializingBean {
085:
086: private WorkManager workManager;
087:
088: private String workManagerName;
089:
090: private WorkListener workListener;
091:
092: /**
093: * Specify the CommonJ WorkManager to delegate to.
094: * <p>Alternatively, you can also specify the JNDI name
095: * of the target WorkManager.
096: * @see #setWorkManagerName
097: */
098: public void setWorkManager(WorkManager workManager) {
099: this .workManager = workManager;
100: }
101:
102: /**
103: * Set the JNDI name of the CommonJ WorkManager.
104: * <p>This can either be a fully qualified JNDI name,
105: * or the JNDI name relative to the current environment
106: * naming context if "resourceRef" is set to "true".
107: * @see #setWorkManager
108: * @see #setResourceRef
109: */
110: public void setWorkManagerName(String workManagerName) {
111: this .workManagerName = workManagerName;
112: }
113:
114: /**
115: * Specify a CommonJ WorkListener to apply, if any.
116: * <p>This shared WorkListener instance will be passed on to the
117: * WorkManager by all {@link #execute} calls on this TaskExecutor.
118: */
119: public void setWorkListener(WorkListener workListener) {
120: this .workListener = workListener;
121: }
122:
123: public void afterPropertiesSet() throws NamingException {
124: if (this .workManager == null) {
125: if (this .workManagerName == null) {
126: throw new IllegalArgumentException(
127: "Either 'workManager' or 'workManagerName' must be specified");
128: }
129: this .workManager = (WorkManager) lookup(
130: this .workManagerName, WorkManager.class);
131: }
132: }
133:
134: //-------------------------------------------------------------------------
135: // Implementation of the Spring SchedulingTaskExecutor interface
136: //-------------------------------------------------------------------------
137:
138: public void execute(Runnable task) {
139: Assert.state(this .workManager != null,
140: "No WorkManager specified");
141: Work work = new DelegatingWork(task);
142: try {
143: if (this .workListener != null) {
144: this .workManager.schedule(work, this .workListener);
145: } else {
146: this .workManager.schedule(work);
147: }
148: } catch (WorkRejectedException ex) {
149: throw new TaskRejectedException(
150: "CommonJ WorkManager did not accept task: " + task,
151: ex);
152: } catch (WorkException ex) {
153: throw new SchedulingException(
154: "Could not schedule task on CommonJ WorkManager",
155: ex);
156: }
157: }
158:
159: /**
160: * This task executor prefers short-lived work units.
161: */
162: public boolean prefersShortLivedTasks() {
163: return true;
164: }
165:
166: //-------------------------------------------------------------------------
167: // Implementation of the CommonJ WorkManager interface
168: //-------------------------------------------------------------------------
169:
170: public WorkItem schedule(Work work) throws WorkException,
171: IllegalArgumentException {
172:
173: return this .workManager.schedule(work);
174: }
175:
176: public WorkItem schedule(Work work, WorkListener workListener)
177: throws WorkException, IllegalArgumentException {
178:
179: return this .workManager.schedule(work, workListener);
180: }
181:
182: public boolean waitForAll(Collection workItems, long timeout)
183: throws InterruptedException, IllegalArgumentException {
184:
185: return this .workManager.waitForAll(workItems, timeout);
186: }
187:
188: public Collection waitForAny(Collection workItems, long timeout)
189: throws InterruptedException, IllegalArgumentException {
190:
191: return this.workManager.waitForAny(workItems, timeout);
192: }
193:
194: }
|