001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.jca;
030:
031: import com.caucho.log.Log;
032: import com.caucho.util.Alarm;
033: import com.caucho.util.L10N;
034: import com.caucho.util.ThreadPool;
035:
036: import javax.resource.spi.work.ExecutionContext;
037: import javax.resource.spi.work.Work;
038: import javax.resource.spi.work.WorkEvent;
039: import javax.resource.spi.work.WorkException;
040: import javax.resource.spi.work.WorkListener;
041: import javax.resource.spi.work.WorkManager;
042: import java.util.ArrayList;
043: import java.util.logging.Logger;
044:
045: /**
046: * Implementation of the work manager.
047: */
048: public class WorkManagerImpl implements WorkManager {
049: private static final L10N L = new L10N(WorkManagerImpl.class);
050: private static final Logger log = Log.open(WorkManagerImpl.class);
051:
052: private ArrayList<Work> _activeTasks = new ArrayList<Work>();
053:
054: private volatile boolean _isClosed;
055:
056: /**
057: * Constructor.
058: */
059: WorkManagerImpl() {
060: }
061:
062: /**
063: * Accepts a work instance for processing. The call blocks until
064: * the work instance completes.
065: */
066: public void doWork(Work work) throws WorkException {
067: doWork(work, INDEFINITE, null, null);
068: }
069:
070: /**
071: * Accepts a work instance for processing. The call blocks until
072: * the work instance completes.
073: */
074: public void doWork(Work work, long startTimeout,
075: ExecutionContext context, WorkListener listener)
076: throws WorkException {
077: boolean isStart = false;
078:
079: try {
080: WorkException exn = null;
081:
082: synchronized (this ) {
083: if (_isClosed)
084: exn = new WorkException(
085: L
086: .l("Work task can't be started from closed context."));
087: else if (_activeTasks.contains(work))
088: exn = new WorkException(L
089: .l("Reentrant Work tasks are not allowed."));
090: else {
091: isStart = true;
092:
093: _activeTasks.add(work);
094: }
095: }
096:
097: if (listener == null) {
098: } else if (isStart)
099: listener.workAccepted(new WorkEvent(this ,
100: WorkEvent.WORK_ACCEPTED, work, null, 0));
101: else {
102: listener.workRejected(new WorkEvent(this ,
103: WorkEvent.WORK_REJECTED, work, exn, 0));
104: }
105:
106: if (exn != null)
107: throw exn;
108:
109: if (listener != null)
110: listener.workStarted(new WorkEvent(this ,
111: WorkEvent.WORK_STARTED, work, null, 0));
112:
113: work.run();
114:
115: if (listener != null)
116: listener.workCompleted(new WorkEvent(this ,
117: WorkEvent.WORK_COMPLETED, work, null, 0));
118: } finally {
119: synchronized (this ) {
120: _activeTasks.remove(work);
121: }
122: }
123: }
124:
125: /**
126: * Accepts a work instance for processing. The call blocks until
127: * the work instance starts, but does not wait not until the completion.
128: */
129: public long startWork(Work work) throws WorkException {
130: return startWork(work, INDEFINITE, null, null);
131: }
132:
133: /**
134: * Accepts a work instance for processing. The call blocks until
135: * the work instance starts, but does not wait not until the completion.
136: */
137: public long startWork(Work work, long startTimeout,
138: ExecutionContext context, WorkListener listener)
139: throws WorkException {
140: long start = Alarm.getCurrentTime();
141:
142: startWork(work, startTimeout, context, listener, true);
143:
144: return Alarm.getCurrentTime() - start;
145: }
146:
147: /**
148: * Schedules a work instance.
149: */
150: public void scheduleWork(Work work) throws WorkException {
151: // XXX: since there's no delay in start work, currently,
152: scheduleWork(work, INDEFINITE, null, null);
153: }
154:
155: /**
156: * Schedules a work instance.
157: */
158: public void scheduleWork(Work work, long startTimeout,
159: ExecutionContext context, WorkListener listener)
160: throws WorkException {
161: startWork(work, startTimeout, context, listener, false);
162: }
163:
164: /**
165: * Accepts a work instance for processing. The call blocks until
166: * the work instance starts, but does not wait not until the completion.
167: */
168: private long startWork(Work work, long startTimeout,
169: ExecutionContext context, WorkListener listener,
170: boolean waitForStart) throws WorkException {
171: boolean isStart = false;
172:
173: WorkException exn = null;
174:
175: try {
176: synchronized (this ) {
177: if (_isClosed)
178: exn = new WorkException(
179: L
180: .l("Work task can't be started from closed context."));
181: else if (_activeTasks.contains(work))
182: exn = new WorkException(L
183: .l("Reentrant Work tasks are not allowed."));
184: else
185: _activeTasks.add(work);
186: }
187:
188: if (exn != null) {
189: if (listener != null)
190: listener.workRejected(new WorkEvent(this ,
191: WorkEvent.WORK_REJECTED, work, exn, 0));
192: throw exn;
193: } else if (listener != null)
194: listener.workAccepted(new WorkEvent(this ,
195: WorkEvent.WORK_ACCEPTED, work, null, 0));
196:
197: ClassLoader loader = Thread.currentThread()
198: .getContextClassLoader();
199: WorkThread workThread = new WorkThread(this , work, loader,
200: listener);
201:
202: if (listener != null)
203: listener.workStarted(new WorkEvent(this ,
204: WorkEvent.WORK_STARTED, work, null, 0));
205:
206: if (waitForStart)
207: isStart = ThreadPool.getThreadPool().start(workThread,
208: startTimeout);
209: else
210: isStart = ThreadPool.getThreadPool().schedule(
211: workThread, startTimeout);
212: } finally {
213: synchronized (this ) {
214: if (!isStart)
215: _activeTasks.remove(work);
216: }
217: }
218:
219: return 0;
220: }
221:
222: void completeWork(Work work) {
223: synchronized (this ) {
224: _activeTasks.remove(work);
225: }
226: }
227:
228: /**
229: * Closes the work manager.
230: */
231: public void destroy() {
232: synchronized (this ) {
233: if (_isClosed)
234: return;
235:
236: _isClosed = true;
237: }
238:
239: ArrayList<Work> activeTasks = new ArrayList<Work>();
240:
241: synchronized (this ) {
242: activeTasks.addAll(_activeTasks);
243: }
244:
245: for (int i = 0; i < activeTasks.size(); i++)
246: activeTasks.get(i).release();
247: }
248: }
|