/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jca.ra; import com.caucho.env.thread.ThreadPool; import com.caucho.inject.Module; import com.caucho.util.Alarm; import com.caucho.util.L10N; import javax.resource.spi.work.ExecutionContext; import javax.resource.spi.work.Work; import javax.resource.spi.work.WorkEvent; import javax.resource.spi.work.WorkException; import javax.resource.spi.work.WorkListener; import javax.resource.spi.work.WorkManager; import java.util.ArrayList; /** * Implementation of the work manager. */ @Module public class WorkManagerImpl implements WorkManager { private static final L10N L = new L10N(WorkManagerImpl.class); private ArrayList<Work> _activeTasks = new ArrayList<Work>(); private volatile boolean _isClosed; /** * Constructor. */ WorkManagerImpl() { } /** * Accepts a work instance for processing. The call blocks until * the work instance completes. */ public void doWork(Work work) throws WorkException { doWork(work, INDEFINITE, null, null); } /** * Accepts a work instance for processing. The call blocks until * the work instance completes. */ public void doWork(Work work, long startTimeout, ExecutionContext context, WorkListener listener) throws WorkException { boolean isStart = false; try { WorkException exn = null; synchronized (this) { if (_isClosed) exn = new WorkException(L.l("Work task can't be started from closed context.")); else if (_activeTasks.contains(work)) exn = new WorkException(L.l("Reentrant Work tasks are not allowed.")); else { isStart = true; _activeTasks.add(work); } } if (listener == null) { } else if (isStart) listener.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null, 0)); else { listener.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, exn, 0)); } if (exn != null) throw exn; if (listener != null) listener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, work, null, 0)); work.run(); if (listener != null) listener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, work, null, 0)); } finally { synchronized (this) { _activeTasks.remove(work); } } } /** * Accepts a work instance for processing. The call blocks until * the work instance starts, but does not wait not until the completion. */ public long startWork(Work work) throws WorkException { return startWork(work, INDEFINITE, null, null); } /** * Accepts a work instance for processing. The call blocks until * the work instance starts, but does not wait not until the completion. */ public long startWork(Work work, long startTimeout, ExecutionContext context, WorkListener listener) throws WorkException { long start = Alarm.getCurrentTime(); startWork(work, startTimeout, context, listener, true); return Alarm.getCurrentTime() - start; } /** * Schedules a work instance. */ public void scheduleWork(Work work) throws WorkException { // XXX: since there's no delay in start work, currently, scheduleWork(work, INDEFINITE, null, null); } /** * Schedules a work instance. */ public void scheduleWork(Work work, long startTimeout, ExecutionContext context, WorkListener listener) throws WorkException { startWork(work, startTimeout, context, listener, false); } /** * Accepts a work instance for processing. The call blocks until * the work instance starts, but does not wait not until the completion. */ private long startWork(Work work, long startTimeout, ExecutionContext context, WorkListener listener, boolean waitForStart) throws WorkException { boolean isStart = false; WorkException exn = null; try { synchronized (this) { if (_isClosed) exn = new WorkException(L.l("Work task can't be started from closed context.")); else if (_activeTasks.contains(work)) exn = new WorkException(L.l("Reentrant Work tasks are not allowed.")); else _activeTasks.add(work); } if (exn != null) { if (listener != null) listener.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, work, exn, 0)); throw exn; } else if (listener != null) listener.workAccepted(new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null, 0)); ClassLoader loader = Thread.currentThread().getContextClassLoader(); WorkThread workThread = new WorkThread(this, work, loader, listener); if (listener != null) listener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, work, null, 0)); if (waitForStart) isStart = ThreadPool.getThreadPool().start(workThread, startTimeout); else isStart = ThreadPool.getThreadPool().schedule(workThread, startTimeout); } finally { synchronized (this) { if (! isStart) _activeTasks.remove(work); } } return 0; } void completeWork(Work work) { synchronized (this) { _activeTasks.remove(work); } } /** * Closes the work manager. */ public void destroy() { synchronized (this) { if (_isClosed) return; _isClosed = true; } ArrayList<Work> activeTasks = new ArrayList<Work>(); synchronized (this) { activeTasks.addAll(_activeTasks); } for (int i = 0; i < activeTasks.size(); i++) activeTasks.get(i).release(); } }