/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.dqp.internal.process; import javax.resource.spi.work.Work; import javax.resource.spi.work.WorkEvent; import javax.resource.spi.work.WorkListener; import org.teiid.logging.LogManager; /** * Represents a task that performs work that may take more than one processing pass to complete. * During processing the WorkItem may receive events asynchronously through the moreWork method. */ public abstract class AbstractWorkItem implements Work, WorkListener { enum ThreadState { MORE_WORK, WORKING, IDLE, DONE } private ThreadState threadState = ThreadState.MORE_WORK; private volatile boolean isProcessing; private Object processLock = new Object(); public void run() { startProcessing(); try { synchronized (processLock) { process(); } } finally { endProcessing(); } } synchronized ThreadState getThreadState() { return this.threadState; } public boolean isProcessing() { return isProcessing; } private synchronized void startProcessing() { isProcessing = true; logTrace("start processing"); //$NON-NLS-1$ if (this.threadState != ThreadState.MORE_WORK) { throw new IllegalStateException("Must be in MORE_WORK"); //$NON-NLS-1$ } this.threadState = ThreadState.WORKING; } private synchronized void endProcessing() { isProcessing = false; logTrace("end processing"); //$NON-NLS-1$ switch (this.threadState) { case WORKING: if (isDoneProcessing()) { logTrace("done processing"); //$NON-NLS-1$ this.threadState = ThreadState.DONE; } else { this.threadState = ThreadState.IDLE; pauseProcessing(); } break; case MORE_WORK: if (isDoneProcessing()) { logTrace("done processing - ignoring more"); //$NON-NLS-1$ this.threadState = ThreadState.DONE; } else { resumeProcessing(); } break; default: throw new IllegalStateException("Should not END on " + this.threadState); //$NON-NLS-1$ } } public void moreWork() { moreWork(true); } protected synchronized void moreWork(boolean ignoreDone) { logTrace("more work"); //$NON-NLS-1$ this.notifyAll(); switch (this.threadState) { case WORKING: this.threadState = ThreadState.MORE_WORK; break; case MORE_WORK: break; case IDLE: this.threadState = ThreadState.MORE_WORK; resumeProcessing(); break; default: if (!ignoreDone) { throw new IllegalStateException("More work is not valid once DONE"); //$NON-NLS-1$ } LogManager.logDetail(org.teiid.logging.LogConstants.CTX_DQP, this, "ignoring more work, since the work item is done"); //$NON-NLS-1$ } } private void logTrace(String msg) { LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, this, msg, this.threadState); } protected abstract void process(); protected void pauseProcessing() { } protected abstract void resumeProcessing(); protected abstract boolean isDoneProcessing(); public abstract String toString(); @Override public void release() { } @Override public void workAccepted(WorkEvent arg0) { } @Override public void workCompleted(WorkEvent arg0) { } @Override public void workRejected(WorkEvent event) { } @Override public void workStarted(WorkEvent arg0) { } }